diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 0000000..f52bff7 --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1,2 @@ +# Global Code Owners +* @adthom @Justw-MSFT \ No newline at end of file diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..08d945e --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,11 @@ +--- +version: 2 +updates: +- package-ecosystem: "nuget" + directory: "/" + schedule: + interval: "weekly" +- package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "weekly" \ No newline at end of file diff --git a/.gitignore b/.gitignore index 8a30d25..fbef22c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,13 @@ ## Ignore Visual Studio temporary files, build results, and ## files generated by popular Visual Studio add-ons. -## -## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore + +# Azure Functions localsettings file +local.settings.json + +# Azurite files +__azurite*.json +__blobstorage__/ +__queuestorage__/ # User-specific files *.rsuser @@ -395,4 +401,5 @@ FodyWeavers.xsd *.msp # JetBrains Rider -*.sln.iml +.idea/ +*.sln.iml \ No newline at end of file diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000..bb76300 --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,6 @@ +{ + "recommendations": [ + "ms-azuretools.vscode-azurefunctions", + "ms-dotnettools.csharp" + ] +} \ No newline at end of file diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..071cfe1 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,11 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "name": "Attach to .NET Functions", + "type": "coreclr", + "request": "attach", + "processId": "${command:azureFunctions.pickProcess}" + } + ] +} diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..dfc1e1b --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,21 @@ +{ + "azureFunctions.deploySubpath": "src/bin/Release/net6.0/publish", + "azureFunctions.projectLanguage": "C#", + "azureFunctions.projectRuntime": "~4", + "debug.internalConsoleOptions": "neverOpen", + "azureFunctions.preDeployTask": "publish (functions)", + "files.exclude": { + "**/.git": true, + "**/.svn": true, + "**/.hg": true, + "**/CVS": true, + "**/.DS_Store": true, + "**/Thumbs.db": true, + "**/__azurite_db_blob*.json": true, + "**/__blobstorage__": true, + ".vs": true, + "**/obj": true, + "**/bin": true + }, + "azureFunctions.projectSubpath": "src\\Functions" +} diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 0000000..ce097bd --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,69 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "label": "clean (functions)", + "command": "dotnet", + "args": [ + "clean", + "/property:GenerateFullPaths=true", + "/consoleloggerparameters:NoSummary" + ], + "type": "process", + "problemMatcher": "$msCompile" + }, + { + "label": "build (functions)", + "command": "dotnet", + "args": [ + "build", + "/property:GenerateFullPaths=true", + "/consoleloggerparameters:NoSummary" + ], + "type": "process", + "dependsOn": "clean (functions)", + "group": { + "kind": "build", + "isDefault": true + }, + "problemMatcher": "$msCompile" + }, + { + "label": "clean release (functions)", + "command": "dotnet", + "args": [ + "clean", + "--configuration", + "Release", + "/property:GenerateFullPaths=true", + "/consoleloggerparameters:NoSummary" + ], + "type": "process", + "problemMatcher": "$msCompile" + }, + { + "label": "publish (functions)", + "command": "dotnet", + "args": [ + "publish", + "--configuration", + "Release", + "/property:GenerateFullPaths=true", + "/consoleloggerparameters:NoSummary" + ], + "type": "process", + "dependsOn": "clean release (functions)", + "problemMatcher": "$msCompile" + }, + { + "type": "func", + "dependsOn": "build (functions)", + "options": { + "cwd": "${workspaceFolder}/src/bin/Debug/net6.0" + }, + "command": "host start", + "isBackground": true, + "problemMatcher": "$func-dotnet-watch" + } + ] +} diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index f9ba8cf..6257f2e 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -6,4 +6,4 @@ Resources: - [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/) - [Microsoft Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) -- Contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with questions or concerns +- Contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with questions or concerns \ No newline at end of file diff --git a/CallRecordInsights.sln b/CallRecordInsights.sln new file mode 100644 index 0000000..33cef7d --- /dev/null +++ b/CallRecordInsights.sln @@ -0,0 +1,36 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.6.33801.468 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CallRecordInsights.Functions", "src\Functions\CallRecordInsights.Functions.csproj", "{DD68CDDE-4E23-47E3-8173-2799F7FC7C54}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CallRecordInsights.Flattener", "src\Flattener\CallRecordInsights.Flattener.csproj", "{EA094B49-D23B-457B-A7EC-B4CDD4409F8E}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{EA4A8EC6-E390-476F-A0B4-9B9F4DDD805A}" + ProjectSection(SolutionItems) = preProject + src\.editorconfig = src\.editorconfig + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {DD68CDDE-4E23-47E3-8173-2799F7FC7C54}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DD68CDDE-4E23-47E3-8173-2799F7FC7C54}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DD68CDDE-4E23-47E3-8173-2799F7FC7C54}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DD68CDDE-4E23-47E3-8173-2799F7FC7C54}.Release|Any CPU.Build.0 = Release|Any CPU + {EA094B49-D23B-457B-A7EC-B4CDD4409F8E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {EA094B49-D23B-457B-A7EC-B4CDD4409F8E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {EA094B49-D23B-457B-A7EC-B4CDD4409F8E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {EA094B49-D23B-457B-A7EC-B4CDD4409F8E}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {EFF0E08A-B789-4B7C-AF75-CF9D0FCFC01A} + EndGlobalSection +EndGlobal diff --git a/CallRecordsInsightsThreatModel.tm7 b/CallRecordsInsightsThreatModel.tm7 new file mode 100644 index 0000000..0643799 --- /dev/null +++ b/CallRecordsInsightsThreatModel.tm7 @@ -0,0 +1,4 @@ +DRAWINGSURFACE5391df34-17a6-4ed9-87af-59d10800f0eeDiagramNameDiagram 1DRAWINGSURFACE584d326a-d2ac-4d1f-bd52-54c811c6cce8GE.DS584d326a-d2ac-4d1f-bd52-54c811c6cce8Azure Cosmos DBNameAzure Cosmos DBOut Of Scope71f3d9aa-b8ef-4e54-8126-607a1d903103falseReason For Out Of Scope752473b6-52d4-4776-9a24-202153f7d579Configurable AttributesAPI Typed456e645-5642-41ad-857f-951af1a3d968SelectSQLMongoDBAzure TableCassandra1Azure Cosmos DB Firewall Settingsb646c6da-6894-432a-8925-646ae6d1d0eaSelectAllow access from all networksAllow access from selected networks (including Azure)Allow access from selected networks (excluding Azure)1As Generic Data StoreSE.P.TMCore.AzureDocumentDB1001728152710069fb8454-6039-49f5-a97c-bbacdedbc1dfGE.DS69fb8454-6039-49f5-a97c-bbacdedbc1dfAzure Key VaultNameAzure Key VaultOut Of Scope71f3d9aa-b8ef-4e54-8126-607a1d903103falseReason For Out Of Scope752473b6-52d4-4776-9a24-202153f7d579Configurable AttributesAzure Key Vault Firewall Settingscd610fb8-4fbd-49c0-966f-8b4634b39262SelectAllow access from all networksAllow access from selected networks1Azure Key Vault Audit Logging Enabled78bf9482-5267-41c6-84fd-bac2fb6ca0b9SelectTrueFalse1Authenticating to Key Vaultae94fa17-596d-476e-a283-0afc166dcf26SelectManaged IdentitiesService or User Principal and CertificateService or User Principal and Secret1As Generic Data StoreSE.DS.TMCore.AzureKeyVault100134712361000a8faefe-f02d-4def-be22-484c3f76f904GE.P0a8faefe-f02d-4def-be22-484c3f76f904Azure Data ExplorerNameAzure Data ExplorerOut Of Scope71f3d9aa-b8ef-4e54-8126-607a1d903103falseReason For Out Of Scope752473b6-52d4-4776-9a24-202153f7d579Configurable AttributesAs Generic ProcessSE.P.TMCore.ADE10017761267100fe7b81cf-2ab3-4eb1-ac05-29576b1002ddGE.Pfe7b81cf-2ab3-4eb1-ac05-29576b1002ddAzure Event HubNameAzure Event HubOut Of Scope71f3d9aa-b8ef-4e54-8126-607a1d903103falseReason For Out Of Scope752473b6-52d4-4776-9a24-202153f7d579Configurable AttributesAs Generic ProcessSE.P.TMCore.AzureEventHub1008271644100d37480d8-de0a-4967-b94c-81ace2b9f751GE.Pd37480d8-de0a-4967-b94c-81ace2b9f751Web ApplicationNameCall Record Insights Function AppOut Of Scope71f3d9aa-b8ef-4e54-8126-607a1d903103falseReason For Out Of Scope752473b6-52d4-4776-9a24-202153f7d579Configurable AttributesWeb Application Technologiesf9960f99-8659-4776-90d7-e454ef832db7SelectGenericWeb FormsMVC5MVC60EnvironmentType80fe9520-5f00-4480-ad47-f2fd75dede82SelectOnPremAzure0Processes XMLdf53c172-b70c-412c-9e99-a6fbc10748eeSelectYesNo0As Generic ProcessSE.P.TMCore.WebApp1001306169510087952830-0247-4d6d-b43e-3e2f46f47ed0GE.EI87952830-0247-4d6d-b43e-3e2f46f47ed0BrowserNameBrowserOut Of Scope71f3d9aa-b8ef-4e54-8126-607a1d903103falseReason For Out Of Scope752473b6-52d4-4776-9a24-202153f7d579Configurable AttributesAs Generic External InteractorSE.EI.TMCore.Browser1001273193010049ad6fdf-78cd-4183-ab77-6a0dce224274GE.P49ad6fdf-78cd-4183-ab77-6a0dce224274Web APINameMicrosoft GraphOut Of Scope71f3d9aa-b8ef-4e54-8126-607a1d903103trueReason For Out Of Scope752473b6-52d4-4776-9a24-202153f7d579Configurable AttributesWeb API Technologies1e972c93-2bd6-4915-8f5f-f46fd9f9399dSelectGenericMVC 5MVC 61Hosting environment6c5d51b0-91b1-45ca-aebd-3238f93db3b8SelectOn PremAzure2Identity Provider3175328a-d229-4546-887b-39b914a75dd8SelectADFSAzure AD2As Generic ProcessSE.P.TMCore.WebAPI1008531272100432e06ef-869b-4816-b0b1-6964d81fb3e5GE.P432e06ef-869b-4816-b0b1-6964d81fb3e5Azure ADNameEntra IDOut Of Scope71f3d9aa-b8ef-4e54-8126-607a1d903103falseReason For Out Of Scope752473b6-52d4-4776-9a24-202153f7d579Configurable AttributesAs Generic ProcessSE.P.TMCore.AzureAD10015871224100
Diagram 1
eb01b8b5-eca7-49fb-b49b-c8543287fe9fGE.DFeb01b8b5-eca7-49fb-b49b-c8543287fe9fGeneric Data FlowNameEvent Hub Event NotificationDataflow Order15ccd509-98eb-49ad-b9c2-b4a2926d17800Out Of Scope71f3d9aa-b8ef-4e54-8126-607a1d903103falseReason For Out Of Scope752473b6-52d4-4776-9a24-202153f7d579Configurable AttributesShow Boundary Threats23e2b6f4-fcd8-4e76-a04a-c9ff9aff4f59SelectYesNo0GE.DF1097723SouthEastNorthWestfe7b81cf-2ab3-4eb1-ac05-29576b1002dd908725d37480d8-de0a-4967-b94c-81ace2b9f751132471311444d6c-be68-4888-a1eb-80c1333ee35cGE.DF11444d6c-be68-4888-a1eb-80c1333ee35cRequestNameGET Call Record DetailsDataflow Order15ccd509-98eb-49ad-b9c2-b4a2926d17800Out Of Scope71f3d9aa-b8ef-4e54-8126-607a1d903103falseReason For Out Of Scope752473b6-52d4-4776-9a24-202153f7d579Configurable AttributesAs Generic Data FlowShow Boundary Threats23e2b6f4-fcd8-4e76-a04a-c9ff9aff4f59SelectYesNo0SE.DF.TMCore.Request1549614NorthWestd37480d8-de0a-4967-b94c-81ace2b9f7511356701584d326a-d2ac-4d1f-bd52-54c811c6cce8173357727eb2b22-3949-438d-986b-983fe382b0ebGE.DF27eb2b22-3949-438d-986b-983fe382b0ebGeneric Data FlowNameKusto Ingestion From CosmosDBDataflow Order15ccd509-98eb-49ad-b9c2-b4a2926d17802Out Of Scope71f3d9aa-b8ef-4e54-8126-607a1d903103falseReason For Out Of Scope752473b6-52d4-4776-9a24-202153f7d579Configurable AttributesShow Boundary Threats23e2b6f4-fcd8-4e76-a04a-c9ff9aff4f59SelectYesNo0GE.DF1786428WestNorth0a8faefe-f02d-4def-be22-484c3f76f9041781317584d326a-d2ac-4d1f-bd52-54c811c6cce817785326caed8a3-cf48-48ce-a144-01dd2ed39e44GE.DF6caed8a3-cf48-48ce-a144-01dd2ed39e44Generic Data FlowNamePOST Add or Renew SubscriptionDataflow Order15ccd509-98eb-49ad-b9c2-b4a2926d17800Out Of Scope71f3d9aa-b8ef-4e54-8126-607a1d903103falseReason For Out Of Scope752473b6-52d4-4776-9a24-202153f7d579Configurable AttributesShow Boundary Threats23e2b6f4-fcd8-4e76-a04a-c9ff9aff4f59SelectYesNo0GE.DF1714815SouthEastSouth87952830-0247-4d6d-b43e-3e2f46f47ed013681025d37480d8-de0a-4967-b94c-81ace2b9f75113567907436eb65-9227-43ae-b7fb-f4a21af156faGE.DF7436eb65-9227-43ae-b7fb-f4a21af156faGeneric Data FlowNamePOST SubscriptionDataflow Order15ccd509-98eb-49ad-b9c2-b4a2926d17800Out Of Scope71f3d9aa-b8ef-4e54-8126-607a1d903103falseReason For Out Of Scope752473b6-52d4-4776-9a24-202153f7d579Configurable AttributesShow Boundary Threats23e2b6f4-fcd8-4e76-a04a-c9ff9aff4f59SelectYesNo0GE.DF1126486NorthWestSouthEastd37480d8-de0a-4967-b94c-81ace2b9f751132471349ad6fdf-78cd-4183-ab77-6a0dce224274934353b29d6184-ede8-447d-9e35-d418fff6ce50GE.DFb29d6184-ede8-447d-9e35-d418fff6ce50RequestNameGET Subscription RequestDataflow Order15ccd509-98eb-49ad-b9c2-b4a2926d17800Out Of Scope71f3d9aa-b8ef-4e54-8126-607a1d903103falseReason For Out Of Scope752473b6-52d4-4776-9a24-202153f7d579Configurable AttributesAs Generic Data FlowShow Boundary Threats23e2b6f4-fcd8-4e76-a04a-c9ff9aff4f59SelectYesNo0SE.DF.TMCore.Request1188361NorthWestSouthEastd37480d8-de0a-4967-b94c-81ace2b9f751132471349ad6fdf-78cd-4183-ab77-6a0dce224274934353b97bb647-8252-4b35-ac83-00263906b232GE.DFb97bb647-8252-4b35-ac83-00263906b232Generic Data FlowNameGraph Event Notification PublishingDataflow Order15ccd509-98eb-49ad-b9c2-b4a2926d17800Out Of Scope71f3d9aa-b8ef-4e54-8126-607a1d903103falseReason For Out Of Scope752473b6-52d4-4776-9a24-202153f7d579Configurable AttributesShow Boundary Threats23e2b6f4-fcd8-4e76-a04a-c9ff9aff4f59SelectYesNo0GE.DF874516SouthNorthEast49ad6fdf-78cd-4183-ab77-6a0dce224274903367fe7b81cf-2ab3-4eb1-ac05-29576b1002dd9086621d40d609-61a9-491f-9f3e-4c2f01d7e518GE.DF1d40d609-61a9-491f-9f3e-4c2f01d7e518RequestNameGET Event Hub ConnectionStringDataflow Order15ccd509-98eb-49ad-b9c2-b4a2926d17800Out Of Scope71f3d9aa-b8ef-4e54-8126-607a1d903103falseReason For Out Of Scope752473b6-52d4-4776-9a24-202153f7d579Configurable AttributesAs Generic Data FlowShow Boundary Threats23e2b6f4-fcd8-4e76-a04a-c9ff9aff4f59SelectYesNo0SE.DF.TMCore.Request1107260NorthEastWest49ad6fdf-78cd-4183-ab77-6a0dce22427493429069fb8454-6039-49f5-a97c-bbacdedbc1df1352286b89a5c49-b2ce-4da4-9dc4-a0c40c18dcd3GE.DFb89a5c49-b2ce-4da4-9dc4-a0c40c18dcd3Generic Data FlowNameKey Vault Secret ManagementDataflow Order15ccd509-98eb-49ad-b9c2-b4a2926d17800Out Of Scope71f3d9aa-b8ef-4e54-8126-607a1d903103falseReason For Out Of Scope752473b6-52d4-4776-9a24-202153f7d579Configurable AttributesShow Boundary Threats23e2b6f4-fcd8-4e76-a04a-c9ff9aff4f59SelectYesNo0GE.DF1402593NorthSouthEastd37480d8-de0a-4967-b94c-81ace2b9f751135670169fb8454-6039-49f5-a97c-bbacdedbc1df1442331f1bf866c-8df5-4944-bad7-9d23b80ed08cGE.DFf1bf866c-8df5-4944-bad7-9d23b80ed08cGeneric Data FlowNameUPSERT Call Record DetailsDataflow Order15ccd509-98eb-49ad-b9c2-b4a2926d17800Out Of Scope71f3d9aa-b8ef-4e54-8126-607a1d903103falseReason For Out Of Scope752473b6-52d4-4776-9a24-202153f7d579Configurable AttributesShow Boundary Threats23e2b6f4-fcd8-4e76-a04a-c9ff9aff4f59SelectYesNo0GE.DF1605683NorthEastSouthd37480d8-de0a-4967-b94c-81ace2b9f7511387713584d326a-d2ac-4d1f-bd52-54c811c6cce817786224b289fb1-df89-4d9b-8ab7-b90dc071c68bGE.DF4b289fb1-df89-4d9b-8ab7-b90dc071c68bRequestNameGET Call RecordDataflow Order15ccd509-98eb-49ad-b9c2-b4a2926d17800Out Of Scope71f3d9aa-b8ef-4e54-8126-607a1d903103falseReason For Out Of Scope752473b6-52d4-4776-9a24-202153f7d579Configurable AttributesAs Generic Data FlowShow Boundary Threats23e2b6f4-fcd8-4e76-a04a-c9ff9aff4f59SelectYesNo0SE.DF.TMCore.Request1060610NorthWestSouthEastd37480d8-de0a-4967-b94c-81ace2b9f751132471349ad6fdf-78cd-4183-ab77-6a0dce224274934353970a9b10-b72f-4409-8a0f-9365579d7853GE.DF970a9b10-b72f-4409-8a0f-9365579d7853Generic Data FlowNameGET Health StateDataflow Order15ccd509-98eb-49ad-b9c2-b4a2926d17800Out Of Scope71f3d9aa-b8ef-4e54-8126-607a1d903103falseReason For Out Of Scope752473b6-52d4-4776-9a24-202153f7d579Configurable AttributesShow Boundary Threats23e2b6f4-fcd8-4e76-a04a-c9ff9aff4f59SelectYesNo0GE.DF1170840WestSouth87952830-0247-4d6d-b43e-3e2f46f47ed01278980d37480d8-de0a-4967-b94c-81ace2b9f75113567908708f0cc-7157-441c-b430-d69e15ec1ab9GE.DF8708f0cc-7157-441c-b430-d69e15ec1ab9RequestNameGET OpenId-ConfigurationDataflow Order15ccd509-98eb-49ad-b9c2-b4a2926d17800Out Of Scope71f3d9aa-b8ef-4e54-8126-607a1d903103falseReason For Out Of Scope752473b6-52d4-4776-9a24-202153f7d579Configurable AttributesAs Generic Data FlowShow Boundary Threats23e2b6f4-fcd8-4e76-a04a-c9ff9aff4f59SelectYesNo0SE.DF.TMCore.Request1526469NorthEastSouthd37480d8-de0a-4967-b94c-81ace2b9f7511387713432e06ef-869b-4816-b0b1-6964d81fb3e516373196bdd8677-730d-4713-8037-5aebcf82a6beGE.DF6bdd8677-730d-4713-8037-5aebcf82a6beRequestNameGET Raw Call RecordDataflow Order15ccd509-98eb-49ad-b9c2-b4a2926d17800Out Of Scope71f3d9aa-b8ef-4e54-8126-607a1d903103falseReason For Out Of Scope752473b6-52d4-4776-9a24-202153f7d579Configurable AttributesAs Generic Data FlowShow Boundary Threats23e2b6f4-fcd8-4e76-a04a-c9ff9aff4f59SelectYesNo0SE.DF.TMCore.Request1514834EastSouth87952830-0247-4d6d-b43e-3e2f46f47ed01368980d37480d8-de0a-4967-b94c-81ace2b9f7511356790d682bc87-20a8-4db1-b3c4-226a07278aa3GE.DFd682bc87-20a8-4db1-b3c4-226a07278aa3Generic Data FlowNameGET SubscriptionDataflow Order15ccd509-98eb-49ad-b9c2-b4a2926d17800Out Of Scope71f3d9aa-b8ef-4e54-8126-607a1d903103falseReason For Out Of Scope752473b6-52d4-4776-9a24-202153f7d579Configurable AttributesShow Boundary Threats23e2b6f4-fcd8-4e76-a04a-c9ff9aff4f59SelectYesNo0GE.DF1006878SouthWestSouth87952830-0247-4d6d-b43e-3e2f46f47ed012781025d37480d8-de0a-4967-b94c-81ace2b9f7511356790117f99b4-6aba-4de8-babb-3e686b4faea9GE.DF117f99b4-6aba-4de8-babb-3e686b4faea9Generic Data FlowNamePOST Manually Process Call-IdDataflow Order15ccd509-98eb-49ad-b9c2-b4a2926d17800Out Of Scope71f3d9aa-b8ef-4e54-8126-607a1d903103falseReason For Out Of Scope752473b6-52d4-4776-9a24-202153f7d579Configurable AttributesShow Boundary Threats23e2b6f4-fcd8-4e76-a04a-c9ff9aff4f59SelectYesNo0GE.DF1340835NorthSouth87952830-0247-4d6d-b43e-3e2f46f47ed01323935d37480d8-de0a-4967-b94c-81ace2b9f75113567900.8
TH32fe7b81cf-2ab3-4eb1-ac05-29576b1002ddeb01b8b5-eca7-49fb-b49b-c8543287fe9fd37480d8-de0a-4967-b94c-81ace2b9f7515391df34-17a6-4ed9-87af-59d10800f0eeeb01b8b5-eca7-49fb-b49b-c8543287fe9f15fe7b81cf-2ab3-4eb1-ac05-29576b1002dd:eb01b8b5-eca7-49fb-b49b-c8543287fe9f:d37480d8-de0a-4967-b94c-81ace2b9f7510001-01-01T00:00:00HighTitleAn adversary can spoof the target web application due to insecure TLS certificate configurationUserThreatCategorySpoofingUserThreatShortDescriptionSpoofing is when a process or entity is something other than its claimed identity. Examples include substituting a process, a file, website or a network addressUserThreatDescriptionEnsure that TLS certificate parameters are configured with correct valuesInteractionStringEvent Hub Event NotificationPossibleMitigationsVerify X.509 certificates used to authenticate SSL, TLS, and DTLS connections. Refer: <a href="https://aka.ms/tmtcommsec#x509-ssltls">https://aka.ms/tmtcommsec#x509-ssltls</a>PriorityHighSDLPhaseImplementationfe7b81cf-2ab3-4eb1-ac05-29576b1002ddAutoGeneratedd37480d8-de0a-4967-b94c-81ace2b9f751TH32falsefalseTH30fe7b81cf-2ab3-4eb1-ac05-29576b1002ddeb01b8b5-eca7-49fb-b49b-c8543287fe9fd37480d8-de0a-4967-b94c-81ace2b9f7515391df34-17a6-4ed9-87af-59d10800f0eeeb01b8b5-eca7-49fb-b49b-c8543287fe9f14fe7b81cf-2ab3-4eb1-ac05-29576b1002dd:eb01b8b5-eca7-49fb-b49b-c8543287fe9f:d37480d8-de0a-4967-b94c-81ace2b9f7510001-01-01T00:00:00MediumTitleAttacker can deny the malicious act and remove the attack foot prints leading to repudiation issuesUserThreatCategoryRepudiationUserThreatShortDescriptionRepudiation threats involve an adversary denying that something happenedUserThreatDescriptionProper logging of all security events and user actions builds traceability in a system and denies any possible repudiation issues. In the absence of proper auditing and logging controls, it would become impossible to implement any accountability in a systemInteractionStringEvent Hub Event NotificationPossibleMitigationsEnsure that auditing and logging is enforced on the application. Refer: <a href="https://aka.ms/tmtauditlog#auditing">https://aka.ms/tmtauditlog#auditing</a> Ensure that log rotation and separation are in place. Refer: <a href="https://aka.ms/tmtauditlog#log-rotation">https://aka.ms/tmtauditlog#log-rotation</a> Ensure that Audit and Log Files have Restricted Access. Refer: <a href="https://aka.ms/tmtauditlog#log-restricted-access">https://aka.ms/tmtauditlog#log-restricted-access</a> Ensure that User Management Events are Logged. Refer: <a href="https://aka.ms/tmtauditlog#user-management">https://aka.ms/tmtauditlog#user-management</a>PriorityMediumSDLPhaseImplementationfe7b81cf-2ab3-4eb1-ac05-29576b1002ddAutoGeneratedd37480d8-de0a-4967-b94c-81ace2b9f751TH30falsefalseTH94fe7b81cf-2ab3-4eb1-ac05-29576b1002ddeb01b8b5-eca7-49fb-b49b-c8543287fe9fd37480d8-de0a-4967-b94c-81ace2b9f7515391df34-17a6-4ed9-87af-59d10800f0eeeb01b8b5-eca7-49fb-b49b-c8543287fe9f13fe7b81cf-2ab3-4eb1-ac05-29576b1002dd:eb01b8b5-eca7-49fb-b49b-c8543287fe9f:d37480d8-de0a-4967-b94c-81ace2b9f7510001-01-01T00:00:00HighTitleAn adversary can gain access to sensitive information through error messagesUserThreatCategoryInformation DisclosureUserThreatShortDescriptionInformation disclosure happens when the information can be read by an unauthorized partyUserThreatDescriptionAn adversary can gain access to sensitive data such as the following, through verbose error messages - Server names - Connection strings - Usernames - Passwords - SQL procedures - Details of dynamic SQL failures - Stack trace and lines of code - Variables stored in memory - Drive and folder locations - Application install points - Host configuration settings - Other internal application details InteractionStringEvent Hub Event NotificationPossibleMitigationsDo not expose security details in error messages. Refer: <a href="https://aka.ms/tmtxmgmt#messages">https://aka.ms/tmtxmgmt#messages</a> Implement Default error handling page. Refer: <a href="https://aka.ms/tmtxmgmt#default">https://aka.ms/tmtxmgmt#default</a> Set Deployment Method to Retail in IIS. Refer: <a href="https://aka.ms/tmtxmgmt#deployment">https://aka.ms/tmtxmgmt#deployment</a> Exceptions should fail safely. Refer: <a href="https://aka.ms/tmtxmgmt#fail">https://aka.ms/tmtxmgmt#fail</a> ASP.NET applications must disable tracing and debugging prior to deployment. Refer: <a href="https://aka.ms/tmtconfigmgmt#trace-deploy">https://aka.ms/tmtconfigmgmt#trace-deploy</a> Implement controls to prevent username enumeration. Refer: <a href="https://aka.ms/tmtauthn#controls-username-enum">https://aka.ms/tmtauthn#controls-username-enum</a>PriorityHighSDLPhaseImplementationfe7b81cf-2ab3-4eb1-ac05-29576b1002ddAutoGeneratedd37480d8-de0a-4967-b94c-81ace2b9f751TH94falsefalseTH102fe7b81cf-2ab3-4eb1-ac05-29576b1002ddeb01b8b5-eca7-49fb-b49b-c8543287fe9fd37480d8-de0a-4967-b94c-81ace2b9f7515391df34-17a6-4ed9-87af-59d10800f0eeeb01b8b5-eca7-49fb-b49b-c8543287fe9f12fe7b81cf-2ab3-4eb1-ac05-29576b1002dd:eb01b8b5-eca7-49fb-b49b-c8543287fe9f:d37480d8-de0a-4967-b94c-81ace2b9f7510001-01-01T00:00:00HighTitleAn adversary may gain access to sensitive data from log filesUserThreatCategoryInformation DisclosureUserThreatShortDescriptionInformation disclosure happens when the information can be read by an unauthorized partyUserThreatDescriptionAn adversary may gain access to sensitive data from log filesInteractionStringEvent Hub Event NotificationPossibleMitigationsEnsure that the application does not log sensitive user data. Refer: <a href="https://aka.ms/tmtauditlog#log-sensitive-data">https://aka.ms/tmtauditlog#log-sensitive-data</a> Ensure that Audit and Log Files have Restricted Access. Refer: <a href="https://aka.ms/tmtauditlog#log-restricted-access">https://aka.ms/tmtauditlog#log-restricted-access</a>PriorityHighSDLPhaseImplementationfe7b81cf-2ab3-4eb1-ac05-29576b1002ddAutoGeneratedd37480d8-de0a-4967-b94c-81ace2b9f751TH102falsefalseTH101fe7b81cf-2ab3-4eb1-ac05-29576b1002ddeb01b8b5-eca7-49fb-b49b-c8543287fe9fd37480d8-de0a-4967-b94c-81ace2b9f751REDMOND\justw5391df34-17a6-4ed9-87af-59d10800f0eeeb01b8b5-eca7-49fb-b49b-c8543287fe9f11fe7b81cf-2ab3-4eb1-ac05-29576b1002dd:eb01b8b5-eca7-49fb-b49b-c8543287fe9f:d37480d8-de0a-4967-b94c-81ace2b9f7512024-02-01T11:47:41.6986505-08:00HighTitleAn adversary can reverse weakly encrypted or hashed contentUserThreatCategoryInformation DisclosureUserThreatShortDescriptionInformation disclosure happens when the information can be read by an unauthorized partyUserThreatDescriptionAn adversary can reverse weakly encrypted or hashed contentInteractionStringEvent Hub Event NotificationPossibleMitigationsDo not expose security details in error messages. Refer: <a href="https://aka.ms/tmtxmgmt#messages">https://aka.ms/tmtxmgmt#messages</a> Implement Default error handling page. Refer: <a href="https://aka.ms/tmtxmgmt#default">https://aka.ms/tmtxmgmt#default</a> Set Deployment Method to Retail in IIS. Refer: <a href="https://aka.ms/tmtxmgmt#deployment">https://aka.ms/tmtxmgmt#deployment</a> Use only approved symmetric block ciphers and key lengths. Refer: <a href="https://aka.ms/tmtcrypto#cipher-length">https://aka.ms/tmtcrypto#cipher-length</a> Use approved block cipher modes and initialization vectors for symmetric ciphers. Refer: <a href="https://aka.ms/tmtcrypto#vector-ciphers">https://aka.ms/tmtcrypto#vector-ciphers</a> Use approved asymmetric algorithms, key lengths, and padding. Refer: <a href="https://aka.ms/tmtcrypto#padding">https://aka.ms/tmtcrypto#padding</a> Use approved random number generators. Refer: <a href="https://aka.ms/tmtcrypto#numgen">https://aka.ms/tmtcrypto#numgen</a> Do not use symmetric stream ciphers. Refer: <a href="https://aka.ms/tmtcrypto#stream-ciphers">https://aka.ms/tmtcrypto#stream-ciphers</a> Use approved MAC/HMAC/keyed hash algorithms. Refer: <a href="https://aka.ms/tmtcrypto#mac-hash">https://aka.ms/tmtcrypto#mac-hash</a> Use only approved cryptographic hash functions. Refer: <a href="https://aka.ms/tmtcrypto#hash-functions">https://aka.ms/tmtcrypto#hash-functions</a> Verify X.509 certificates used to authenticate SSL, TLS, and DTLS connections. Refer: <a href="https://aka.ms/tmtcommsec#x509-ssltls">https://aka.ms/tmtcommsec#x509-ssltls</a>PriorityHighSDLPhaseImplementationfe7b81cf-2ab3-4eb1-ac05-29576b1002ddNotApplicabled37480d8-de0a-4967-b94c-81ace2b9f751TH101falsefalseTH7fe7b81cf-2ab3-4eb1-ac05-29576b1002ddeb01b8b5-eca7-49fb-b49b-c8543287fe9fd37480d8-de0a-4967-b94c-81ace2b9f751REDMOND\justw5391df34-17a6-4ed9-87af-59d10800f0eeeb01b8b5-eca7-49fb-b49b-c8543287fe9f16fe7b81cf-2ab3-4eb1-ac05-29576b1002dd:eb01b8b5-eca7-49fb-b49b-c8543287fe9f:d37480d8-de0a-4967-b94c-81ace2b9f7512024-01-31T12:38:44.6626743-08:00HighTitleAn adversary can steal sensitive data like user credentialsUserThreatCategorySpoofingUserThreatShortDescriptionSpoofing is when a process or entity is something other than its claimed identity. Examples include substituting a process, a file, website or a network addressUserThreatDescriptionAttackers can exploit weaknesses in system to steal user credentials. Downstream and upstream components are often accessed by using credentials stored in configuration stores. Attackers may steal the upstream or downstream component credentials. Attackers may steal credentials if, Credentials are stored and sent in clear text, Weak input validation coupled with dynamic sql queries, Password retrieval mechanism are poor, InteractionStringEvent Hub Event NotificationPossibleMitigationsExplicitly disable the autocomplete HTML attribute in sensitive forms and inputs. Refer: <a href="https://aka.ms/tmtdata#autocomplete-input">https://aka.ms/tmtdata#autocomplete-input</a> Perform input validation and filtering on all string type Model properties. Refer: <a href="https://aka.ms/tmtinputval#typemodel">https://aka.ms/tmtinputval#typemodel</a> Validate all redirects within the application are closed or done safely. Refer: <a href="https://aka.ms/tmtinputval#redirect-safe">https://aka.ms/tmtinputval#redirect-safe</a> Enable step up or adaptive authentication. Refer: <a href="https://aka.ms/tmtauthn#step-up-adaptive-authn">https://aka.ms/tmtauthn#step-up-adaptive-authn</a> Implement forgot password functionalities securely. Refer: <a href="https://aka.ms/tmtauthn#forgot-pword-fxn">https://aka.ms/tmtauthn#forgot-pword-fxn</a> Ensure that password and account policy are implemented. Refer: <a href="https://aka.ms/tmtauthn#pword-account-policy">https://aka.ms/tmtauthn#pword-account-policy</a> Implement input validation on all string type parameters accepted by Controller methods. Refer: <a href="https://aka.ms/tmtinputval#string-method">https://aka.ms/tmtinputval#string-method</a>PriorityHighSDLPhaseImplementationfe7b81cf-2ab3-4eb1-ac05-29576b1002ddAutoGeneratedd37480d8-de0a-4967-b94c-81ace2b9f751TH7falsefalseTH81fe7b81cf-2ab3-4eb1-ac05-29576b1002ddeb01b8b5-eca7-49fb-b49b-c8543287fe9fd37480d8-de0a-4967-b94c-81ace2b9f7515391df34-17a6-4ed9-87af-59d10800f0eeeb01b8b5-eca7-49fb-b49b-c8543287fe9f17fe7b81cf-2ab3-4eb1-ac05-29576b1002dd:eb01b8b5-eca7-49fb-b49b-c8543287fe9f:d37480d8-de0a-4967-b94c-81ace2b9f7510001-01-01T00:00:00HighTitleAn adversary can create a fake website and launch phishing attacksUserThreatCategorySpoofingUserThreatShortDescriptionSpoofing is when a process or entity is something other than its claimed identity. Examples include substituting a process, a file, website or a network addressUserThreatDescriptionPhishing is attempted to obtain sensitive information such as usernames, passwords, and credit card details (and sometimes, indirectly, money), often for malicious reasons, by masquerading as a Web Server which is a trustworthy entity in electronic communicationInteractionStringEvent Hub Event NotificationPossibleMitigationsVerify X.509 certificates used to authenticate SSL, TLS, and DTLS connections. Refer: <a href="https://aka.ms/tmtcommsec#x509-ssltls">https://aka.ms/tmtcommsec#x509-ssltls</a> Ensure that authenticated ASP.NET pages incorporate UI Redressing or clickjacking defences. Refer: <a href="https://aka.ms/tmtconfigmgmt#ui-defenses">https://aka.ms/tmtconfigmgmt#ui-defenses</a> Validate all redirects within the application are closed or done safely. Refer: <a href="https://aka.ms/tmtinputval#redirect-safe">https://aka.ms/tmtinputval#redirect-safe</a>PriorityHighSDLPhaseImplementationfe7b81cf-2ab3-4eb1-ac05-29576b1002ddAutoGeneratedd37480d8-de0a-4967-b94c-81ace2b9f751TH81falsefalseTH86fe7b81cf-2ab3-4eb1-ac05-29576b1002ddeb01b8b5-eca7-49fb-b49b-c8543287fe9fd37480d8-de0a-4967-b94c-81ace2b9f7515391df34-17a6-4ed9-87af-59d10800f0eeeb01b8b5-eca7-49fb-b49b-c8543287fe9f18fe7b81cf-2ab3-4eb1-ac05-29576b1002dd:eb01b8b5-eca7-49fb-b49b-c8543287fe9f:d37480d8-de0a-4967-b94c-81ace2b9f7510001-01-01T00:00:00HighTitleAn adversary may spoof Azure Event Hub and gain access to Web ApplicationUserThreatCategorySpoofingUserThreatShortDescriptionSpoofing is when a process or entity is something other than its claimed identity. Examples include substituting a process, a file, website or a network addressUserThreatDescriptionIf proper authentication is not in place, an adversary can spoof a source process or external entity and gain unauthorized access to the Web ApplicationInteractionStringEvent Hub Event NotificationPossibleMitigationsConsider using a standard authentication mechanism to authenticate to Web Application. Refer: <a href="https://aka.ms/tmtauthn#standard-authn-web-app">https://aka.ms/tmtauthn#standard-authn-web-app</a>PriorityHighSDLPhaseDesignfe7b81cf-2ab3-4eb1-ac05-29576b1002ddAutoGeneratedd37480d8-de0a-4967-b94c-81ace2b9f751TH86falsefalseTH96fe7b81cf-2ab3-4eb1-ac05-29576b1002ddeb01b8b5-eca7-49fb-b49b-c8543287fe9fd37480d8-de0a-4967-b94c-81ace2b9f7515391df34-17a6-4ed9-87af-59d10800f0eeeb01b8b5-eca7-49fb-b49b-c8543287fe9f19fe7b81cf-2ab3-4eb1-ac05-29576b1002dd:eb01b8b5-eca7-49fb-b49b-c8543287fe9f:d37480d8-de0a-4967-b94c-81ace2b9f7510001-01-01T00:00:00HighTitleAn adversary can gain access to sensitive data by performing SQL injection through Web AppUserThreatCategoryTamperingUserThreatShortDescriptionTampering is the act of altering the bits. Tampering with a process involves changing bits in the running process. Similarly, Tampering with a data flow involves changing bits on the wire or between two running processesUserThreatDescriptionSQL injection is an attack in which malicious code is inserted into strings that are later passed to an instance of SQL Server for parsing and execution. The primary form of SQL injection consists of direct insertion of code into user-input variables that are concatenated with SQL commands and executed. A less direct attack injects malicious code into strings that are destined for storage in a table or as metadata. When the stored strings are subsequently concatenated into a dynamic SQL command, the malicious code is executed. InteractionStringEvent Hub Event NotificationPossibleMitigationsEnsure that type-safe parameters are used in Web Application for data access. Refer: <a href="https://aka.ms/tmtinputval#typesafe">https://aka.ms/tmtinputval#typesafe</a>PriorityHighSDLPhaseImplementationfe7b81cf-2ab3-4eb1-ac05-29576b1002ddAutoGeneratedd37480d8-de0a-4967-b94c-81ace2b9f751TH96falsefalseTH98fe7b81cf-2ab3-4eb1-ac05-29576b1002ddeb01b8b5-eca7-49fb-b49b-c8543287fe9fd37480d8-de0a-4967-b94c-81ace2b9f7515391df34-17a6-4ed9-87af-59d10800f0eeeb01b8b5-eca7-49fb-b49b-c8543287fe9f20fe7b81cf-2ab3-4eb1-ac05-29576b1002dd:eb01b8b5-eca7-49fb-b49b-c8543287fe9f:d37480d8-de0a-4967-b94c-81ace2b9f7510001-01-01T00:00:00HighTitleAn adversary can gain access to sensitive data stored in Web App's config filesUserThreatCategoryTamperingUserThreatShortDescriptionTampering is the act of altering the bits. Tampering with a process involves changing bits in the running process. Similarly, Tampering with a data flow involves changing bits on the wire or between two running processesUserThreatDescriptionAn adversary can gain access to the config files. and if sensitive data is stored in it, it would be compromised.InteractionStringEvent Hub Event NotificationPossibleMitigationsEncrypt sections of Web App's configuration files that contain sensitive data. Refer: <a href="https://aka.ms/tmtdata#encrypt-data">https://aka.ms/tmtdata#encrypt-data</a>PriorityHighSDLPhaseImplementationfe7b81cf-2ab3-4eb1-ac05-29576b1002ddAutoGeneratedd37480d8-de0a-4967-b94c-81ace2b9f751TH98falsefalseTH10387952830-0247-4d6d-b43e-3e2f46f47ed0970a9b10-b72f-4409-8a0f-9365579d7853d37480d8-de0a-4967-b94c-81ace2b9f7515391df34-17a6-4ed9-87af-59d10800f0ee970a9b10-b72f-4409-8a0f-9365579d785317087952830-0247-4d6d-b43e-3e2f46f47ed0:970a9b10-b72f-4409-8a0f-9365579d7853:d37480d8-de0a-4967-b94c-81ace2b9f7510001-01-01T00:00:00HighTitleAn adversary may gain access to unmasked sensitive data such as credit card numbersUserThreatCategoryInformation DisclosureUserThreatShortDescriptionInformation disclosure happens when the information can be read by an unauthorized partyUserThreatDescriptionAn adversary may gain access to unmasked sensitive data such as credit card numbersInteractionStringGET Health StatePossibleMitigationsEnsure that sensitive data displayed on the user screen is masked. Refer: <a href="https://aka.ms/tmtdata#data-mask">https://aka.ms/tmtdata#data-mask</a>PriorityHighSDLPhaseImplementation87952830-0247-4d6d-b43e-3e2f46f47ed0AutoGeneratedd37480d8-de0a-4967-b94c-81ace2b9f751TH103falsefalseTH10287952830-0247-4d6d-b43e-3e2f46f47ed0970a9b10-b72f-4409-8a0f-9365579d7853d37480d8-de0a-4967-b94c-81ace2b9f7515391df34-17a6-4ed9-87af-59d10800f0ee970a9b10-b72f-4409-8a0f-9365579d785316987952830-0247-4d6d-b43e-3e2f46f47ed0:970a9b10-b72f-4409-8a0f-9365579d7853:d37480d8-de0a-4967-b94c-81ace2b9f7510001-01-01T00:00:00HighTitleAn adversary may gain access to sensitive data from log filesUserThreatCategoryInformation DisclosureUserThreatShortDescriptionInformation disclosure happens when the information can be read by an unauthorized partyUserThreatDescriptionAn adversary may gain access to sensitive data from log filesInteractionStringGET Health StatePossibleMitigationsEnsure that the application does not log sensitive user data. Refer: <a href="https://aka.ms/tmtauditlog#log-sensitive-data">https://aka.ms/tmtauditlog#log-sensitive-data</a> Ensure that Audit and Log Files have Restricted Access. Refer: <a href="https://aka.ms/tmtauditlog#log-restricted-access">https://aka.ms/tmtauditlog#log-restricted-access</a>PriorityHighSDLPhaseImplementation87952830-0247-4d6d-b43e-3e2f46f47ed0AutoGeneratedd37480d8-de0a-4967-b94c-81ace2b9f751TH102falsefalseTH10187952830-0247-4d6d-b43e-3e2f46f47ed0970a9b10-b72f-4409-8a0f-9365579d7853d37480d8-de0a-4967-b94c-81ace2b9f7515391df34-17a6-4ed9-87af-59d10800f0ee970a9b10-b72f-4409-8a0f-9365579d785316887952830-0247-4d6d-b43e-3e2f46f47ed0:970a9b10-b72f-4409-8a0f-9365579d7853:d37480d8-de0a-4967-b94c-81ace2b9f7510001-01-01T00:00:00HighTitleAn adversary can reverse weakly encrypted or hashed contentUserThreatCategoryInformation DisclosureUserThreatShortDescriptionInformation disclosure happens when the information can be read by an unauthorized partyUserThreatDescriptionAn adversary can reverse weakly encrypted or hashed contentInteractionStringGET Health StatePossibleMitigationsDo not expose security details in error messages. Refer: <a href="https://aka.ms/tmtxmgmt#messages">https://aka.ms/tmtxmgmt#messages</a> Implement Default error handling page. Refer: <a href="https://aka.ms/tmtxmgmt#default">https://aka.ms/tmtxmgmt#default</a> Set Deployment Method to Retail in IIS. Refer: <a href="https://aka.ms/tmtxmgmt#deployment">https://aka.ms/tmtxmgmt#deployment</a> Use only approved symmetric block ciphers and key lengths. Refer: <a href="https://aka.ms/tmtcrypto#cipher-length">https://aka.ms/tmtcrypto#cipher-length</a> Use approved block cipher modes and initialization vectors for symmetric ciphers. Refer: <a href="https://aka.ms/tmtcrypto#vector-ciphers">https://aka.ms/tmtcrypto#vector-ciphers</a> Use approved asymmetric algorithms, key lengths, and padding. Refer: <a href="https://aka.ms/tmtcrypto#padding">https://aka.ms/tmtcrypto#padding</a> Use approved random number generators. Refer: <a href="https://aka.ms/tmtcrypto#numgen">https://aka.ms/tmtcrypto#numgen</a> Do not use symmetric stream ciphers. Refer: <a href="https://aka.ms/tmtcrypto#stream-ciphers">https://aka.ms/tmtcrypto#stream-ciphers</a> Use approved MAC/HMAC/keyed hash algorithms. Refer: <a href="https://aka.ms/tmtcrypto#mac-hash">https://aka.ms/tmtcrypto#mac-hash</a> Use only approved cryptographic hash functions. Refer: <a href="https://aka.ms/tmtcrypto#hash-functions">https://aka.ms/tmtcrypto#hash-functions</a> Verify X.509 certificates used to authenticate SSL, TLS, and DTLS connections. Refer: <a href="https://aka.ms/tmtcommsec#x509-ssltls">https://aka.ms/tmtcommsec#x509-ssltls</a>PriorityHighSDLPhaseImplementation87952830-0247-4d6d-b43e-3e2f46f47ed0AutoGeneratedd37480d8-de0a-4967-b94c-81ace2b9f751TH101falsefalseTH2787952830-0247-4d6d-b43e-3e2f46f47ed0970a9b10-b72f-4409-8a0f-9365579d7853d37480d8-de0a-4967-b94c-81ace2b9f7515391df34-17a6-4ed9-87af-59d10800f0ee970a9b10-b72f-4409-8a0f-9365579d785316787952830-0247-4d6d-b43e-3e2f46f47ed0:970a9b10-b72f-4409-8a0f-9365579d7853:d37480d8-de0a-4967-b94c-81ace2b9f7510001-01-01T00:00:00HighTitleAn adversary may bypass critical steps or perform actions on behalf of other users (victims) due to improper validation logicUserThreatCategoryElevation of PrivilegesUserThreatShortDescriptionA user subject gains increased capability or privilege by taking advantage of an implementation bugUserThreatDescriptionFailure to restrict the privileges and access rights to the application to individuals who require the privileges or access rights may result into unauthorized use of data due to inappropriate rights settings and validation.InteractionStringGET Health StatePossibleMitigationsEnsure that administrative interfaces are appropriately locked down. Refer: <a href="https://aka.ms/tmtauthn#admin-interface-lockdown">https://aka.ms/tmtauthn#admin-interface-lockdown</a> Enforce sequential step order when processing business logic flows. Refer: <a href="https://aka.ms/tmtauthz#sequential-logic">https://aka.ms/tmtauthz#sequential-logic</a> Ensure that proper authorization is in place and principle of least privileges is followed. Refer: <a href="https://aka.ms/tmtauthz#principle-least-privilege">https://aka.ms/tmtauthz#principle-least-privilege</a> Business logic and resource access authorization decisions should not be based on incoming request parameters. Refer: <a href="https://aka.ms/tmtauthz#logic-request-parameters">https://aka.ms/tmtauthz#logic-request-parameters</a> Ensure that content and resources are not enumerable or accessible via forceful browsing. Refer: <a href="https://aka.ms/tmtauthz#enumerable-browsing">https://aka.ms/tmtauthz#enumerable-browsing</a>PriorityHighSDLPhaseImplementation87952830-0247-4d6d-b43e-3e2f46f47ed0AutoGeneratedd37480d8-de0a-4967-b94c-81ace2b9f751TH27falsefalseTH2687952830-0247-4d6d-b43e-3e2f46f47ed0970a9b10-b72f-4409-8a0f-9365579d7853d37480d8-de0a-4967-b94c-81ace2b9f7515391df34-17a6-4ed9-87af-59d10800f0ee970a9b10-b72f-4409-8a0f-9365579d785316687952830-0247-4d6d-b43e-3e2f46f47ed0:970a9b10-b72f-4409-8a0f-9365579d7853:d37480d8-de0a-4967-b94c-81ace2b9f7510001-01-01T00:00:00HighTitleAn adversary can perform action on behalf of other user due to lack of controls against cross domain requestsUserThreatCategoryDenial of ServiceUserThreatShortDescriptionDenial of Service happens when the process or a datastore is not able to service incoming requests or perform up to specUserThreatDescriptionFailure to restrict requests originating from third party domains may result in unauthorized actions or access of dataInteractionStringGET Health StatePossibleMitigationsEnsure that authenticated ASP.NET pages incorporate UI Redressing or clickjacking defences. Refer: <a href="https://aka.ms/tmtconfigmgmt#ui-defenses">https://aka.ms/tmtconfigmgmt#ui-defenses</a> Ensure that only trusted origins are allowed if CORS is enabled on ASP.NET Web Applications. Refer: <a href="https://aka.ms/tmtconfigmgmt#cors-aspnet">https://aka.ms/tmtconfigmgmt#cors-aspnet</a> Mitigate against Cross-Site Request Forgery (CSRF) attacks on ASP.NET web pages. Refer: <a href="https://aka.ms/tmtsmgmt#csrf-asp">https://aka.ms/tmtsmgmt#csrf-asp</a>PriorityHighSDLPhaseImplementation87952830-0247-4d6d-b43e-3e2f46f47ed0AutoGeneratedd37480d8-de0a-4967-b94c-81ace2b9f751TH26falsefalseTH550a8faefe-f02d-4def-be22-484c3f76f90427eb2b22-3949-438d-986b-983fe382b0eb584d326a-d2ac-4d1f-bd52-54c811c6cce85391df34-17a6-4ed9-87af-59d10800f0ee27eb2b22-3949-438d-986b-983fe382b0eb1210a8faefe-f02d-4def-be22-484c3f76f904:27eb2b22-3949-438d-986b-983fe382b0eb:584d326a-d2ac-4d1f-bd52-54c811c6cce80001-01-01T00:00:00HighTitleAn adversary may reuse a stolen long-lived resource token, access key or connection string to access an Azure Cosmos DB instanceUserThreatCategoryElevation of PrivilegesUserThreatShortDescriptionA user subject gains increased capability or privilege by taking advantage of an implementation bugUserThreatDescriptionAn adversary may reuse a stolen long-lived resource token, access key or connection string to access an Azure Cosmos DB instanceInteractionStringKusto Ingestion From CosmosDBPossibleMitigationsUse minimum token lifetimes for generated resource tokens. Rotate secrets (e.g. resource tokens, access keys and passwords in connection strings) frequently, in accordance with your organization's policies. Refer: <a href="https://aka.ms/tmt-th55">https://aka.ms/tmt-th55</a>PriorityHighSDLPhaseImplementation0a8faefe-f02d-4def-be22-484c3f76f904AutoGenerated584d326a-d2ac-4d1f-bd52-54c811c6cce8TH55falsefalseTH530a8faefe-f02d-4def-be22-484c3f76f90427eb2b22-3949-438d-986b-983fe382b0eb584d326a-d2ac-4d1f-bd52-54c811c6cce85391df34-17a6-4ed9-87af-59d10800f0ee27eb2b22-3949-438d-986b-983fe382b0eb1200a8faefe-f02d-4def-be22-484c3f76f904:27eb2b22-3949-438d-986b-983fe382b0eb:584d326a-d2ac-4d1f-bd52-54c811c6cce80001-01-01T00:00:00HighTitleAn adversary having access to Azure Cosmos DB may read sensitive clear-text dataUserThreatCategoryInformation DisclosureUserThreatShortDescriptionInformation disclosure happens when the information can be read by an unauthorized partyUserThreatDescriptionAn adversary having access to Azure Cosmos DB may read sensitive clear-text dataInteractionStringKusto Ingestion From CosmosDBPossibleMitigationsEncrypt sensitive data before storing it in Azure Document DB.PriorityHighSDLPhaseDesign0a8faefe-f02d-4def-be22-484c3f76f904AutoGenerated584d326a-d2ac-4d1f-bd52-54c811c6cce8TH53falsefalseTH570a8faefe-f02d-4def-be22-484c3f76f90427eb2b22-3949-438d-986b-983fe382b0eb584d326a-d2ac-4d1f-bd52-54c811c6cce85391df34-17a6-4ed9-87af-59d10800f0ee27eb2b22-3949-438d-986b-983fe382b0eb1190a8faefe-f02d-4def-be22-484c3f76f904:27eb2b22-3949-438d-986b-983fe382b0eb:584d326a-d2ac-4d1f-bd52-54c811c6cce80001-01-01T00:00:00HighTitleAn adversary can gain unauthorized access to Azure Cosmos DB instances due to weak network security configurationUserThreatCategoryElevation of PrivilegesUserThreatShortDescriptionA user subject gains increased capability or privilege by taking advantage of an implementation bugUserThreatDescriptionAn adversary can gain unauthorized access to Azure Cosmos DB instances due to weak network security configurationInteractionStringKusto Ingestion From CosmosDBPossibleMitigationsRestrict access to Azure Cosmos DB instances by configuring account-level firewall rules to only permit connections from selected IP addresses where possible. Refer: <a href="https://aka.ms/tmt-th57">https://aka.ms/tmt-th57</a>PriorityHighSDLPhaseImplementation0a8faefe-f02d-4def-be22-484c3f76f904AutoGenerated584d326a-d2ac-4d1f-bd52-54c811c6cce8TH57falsefalseTH560a8faefe-f02d-4def-be22-484c3f76f90427eb2b22-3949-438d-986b-983fe382b0eb584d326a-d2ac-4d1f-bd52-54c811c6cce85391df34-17a6-4ed9-87af-59d10800f0ee27eb2b22-3949-438d-986b-983fe382b0eb1180a8faefe-f02d-4def-be22-484c3f76f904:27eb2b22-3949-438d-986b-983fe382b0eb:584d326a-d2ac-4d1f-bd52-54c811c6cce80001-01-01T00:00:00HighTitleAn adversary may read content stored in Azure Cosmos DB instances through SQL injection based attacksUserThreatCategoryInformation DisclosureUserThreatShortDescriptionInformation disclosure happens when the information can be read by an unauthorized partyUserThreatDescriptionAn adversary may read content stored in Azure Cosmos DB instances through SQL injection based attacksInteractionStringKusto Ingestion From CosmosDBPossibleMitigationsUse parametrized SQL queries to query Cosmos DB instances. Refer: <a href="https://aka.ms/tmt-th56">https://aka.ms/tmt-th56</a>PriorityHighSDLPhaseImplementation0a8faefe-f02d-4def-be22-484c3f76f904AutoGenerated584d326a-d2ac-4d1f-bd52-54c811c6cce8TH56falsefalseTH540a8faefe-f02d-4def-be22-484c3f76f90427eb2b22-3949-438d-986b-983fe382b0eb584d326a-d2ac-4d1f-bd52-54c811c6cce85391df34-17a6-4ed9-87af-59d10800f0ee27eb2b22-3949-438d-986b-983fe382b0eb1170a8faefe-f02d-4def-be22-484c3f76f904:27eb2b22-3949-438d-986b-983fe382b0eb:584d326a-d2ac-4d1f-bd52-54c811c6cce80001-01-01T00:00:00HighTitleA compromised access key may permit an adversary to have more access than intended to an Azure Cosmos DB instance UserThreatCategoryElevation of PrivilegesUserThreatShortDescriptionA user subject gains increased capability or privilege by taking advantage of an implementation bugUserThreatDescriptionA compromised access key may permit an adversary to have over-privileged access to an Azure Cosmos DB instance InteractionStringKusto Ingestion From CosmosDBPossibleMitigationsUse resource (SAS like) tokens (derived using master keys) to connect to Cosmos DB instances whenever possible. Scope the resource tokens to permit only the privileges necessary (e.g. read-only). Store secrets in a secret storage solution (e.g. Azure Key Vault). Refer: <a href="https://aka.ms/tmt-th54">https://aka.ms/tmt-th54</a> PriorityHighSDLPhaseDesign0a8faefe-f02d-4def-be22-484c3f76f904AutoGenerated584d326a-d2ac-4d1f-bd52-54c811c6cce8TH54falsefalseTH55d37480d8-de0a-4967-b94c-81ace2b9f75111444d6c-be68-4888-a1eb-80c1333ee35c584d326a-d2ac-4d1f-bd52-54c811c6cce85391df34-17a6-4ed9-87af-59d10800f0ee11444d6c-be68-4888-a1eb-80c1333ee35c126d37480d8-de0a-4967-b94c-81ace2b9f751:11444d6c-be68-4888-a1eb-80c1333ee35c:584d326a-d2ac-4d1f-bd52-54c811c6cce80001-01-01T00:00:00HighTitleAn adversary may reuse a stolen long-lived resource token, access key or connection string to access an Azure Cosmos DB instanceUserThreatCategoryElevation of PrivilegesUserThreatShortDescriptionA user subject gains increased capability or privilege by taking advantage of an implementation bugUserThreatDescriptionAn adversary may reuse a stolen long-lived resource token, access key or connection string to access an Azure Cosmos DB instanceInteractionStringGET Call Record DetailsPossibleMitigationsUse minimum token lifetimes for generated resource tokens. Rotate secrets (e.g. resource tokens, access keys and passwords in connection strings) frequently, in accordance with your organization's policies. Refer: <a href="https://aka.ms/tmt-th55">https://aka.ms/tmt-th55</a>PriorityHighSDLPhaseImplementationd37480d8-de0a-4967-b94c-81ace2b9f751AutoGenerated584d326a-d2ac-4d1f-bd52-54c811c6cce8TH55falsefalseTH53d37480d8-de0a-4967-b94c-81ace2b9f75111444d6c-be68-4888-a1eb-80c1333ee35c584d326a-d2ac-4d1f-bd52-54c811c6cce85391df34-17a6-4ed9-87af-59d10800f0ee11444d6c-be68-4888-a1eb-80c1333ee35c125d37480d8-de0a-4967-b94c-81ace2b9f751:11444d6c-be68-4888-a1eb-80c1333ee35c:584d326a-d2ac-4d1f-bd52-54c811c6cce80001-01-01T00:00:00HighTitleAn adversary having access to Azure Cosmos DB may read sensitive clear-text dataUserThreatCategoryInformation DisclosureUserThreatShortDescriptionInformation disclosure happens when the information can be read by an unauthorized partyUserThreatDescriptionAn adversary having access to Azure Cosmos DB may read sensitive clear-text dataInteractionStringGET Call Record DetailsPossibleMitigationsEncrypt sensitive data before storing it in Azure Document DB.PriorityHighSDLPhaseDesignd37480d8-de0a-4967-b94c-81ace2b9f751AutoGenerated584d326a-d2ac-4d1f-bd52-54c811c6cce8TH53falsefalseTH57d37480d8-de0a-4967-b94c-81ace2b9f75111444d6c-be68-4888-a1eb-80c1333ee35c584d326a-d2ac-4d1f-bd52-54c811c6cce85391df34-17a6-4ed9-87af-59d10800f0ee11444d6c-be68-4888-a1eb-80c1333ee35c124d37480d8-de0a-4967-b94c-81ace2b9f751:11444d6c-be68-4888-a1eb-80c1333ee35c:584d326a-d2ac-4d1f-bd52-54c811c6cce80001-01-01T00:00:00HighTitleAn adversary can gain unauthorized access to Azure Cosmos DB instances due to weak network security configurationUserThreatCategoryElevation of PrivilegesUserThreatShortDescriptionA user subject gains increased capability or privilege by taking advantage of an implementation bugUserThreatDescriptionAn adversary can gain unauthorized access to Azure Cosmos DB instances due to weak network security configurationInteractionStringGET Call Record DetailsPossibleMitigationsRestrict access to Azure Cosmos DB instances by configuring account-level firewall rules to only permit connections from selected IP addresses where possible. Refer: <a href="https://aka.ms/tmt-th57">https://aka.ms/tmt-th57</a>PriorityHighSDLPhaseImplementationd37480d8-de0a-4967-b94c-81ace2b9f751AutoGenerated584d326a-d2ac-4d1f-bd52-54c811c6cce8TH57falsefalseTH56d37480d8-de0a-4967-b94c-81ace2b9f75111444d6c-be68-4888-a1eb-80c1333ee35c584d326a-d2ac-4d1f-bd52-54c811c6cce85391df34-17a6-4ed9-87af-59d10800f0ee11444d6c-be68-4888-a1eb-80c1333ee35c123d37480d8-de0a-4967-b94c-81ace2b9f751:11444d6c-be68-4888-a1eb-80c1333ee35c:584d326a-d2ac-4d1f-bd52-54c811c6cce80001-01-01T00:00:00HighTitleAn adversary may read content stored in Azure Cosmos DB instances through SQL injection based attacksUserThreatCategoryInformation DisclosureUserThreatShortDescriptionInformation disclosure happens when the information can be read by an unauthorized partyUserThreatDescriptionAn adversary may read content stored in Azure Cosmos DB instances through SQL injection based attacksInteractionStringGET Call Record DetailsPossibleMitigationsUse parametrized SQL queries to query Cosmos DB instances. Refer: <a href="https://aka.ms/tmt-th56">https://aka.ms/tmt-th56</a>PriorityHighSDLPhaseImplementationd37480d8-de0a-4967-b94c-81ace2b9f751AutoGenerated584d326a-d2ac-4d1f-bd52-54c811c6cce8TH56falsefalseTH54d37480d8-de0a-4967-b94c-81ace2b9f75111444d6c-be68-4888-a1eb-80c1333ee35c584d326a-d2ac-4d1f-bd52-54c811c6cce85391df34-17a6-4ed9-87af-59d10800f0ee11444d6c-be68-4888-a1eb-80c1333ee35c122d37480d8-de0a-4967-b94c-81ace2b9f751:11444d6c-be68-4888-a1eb-80c1333ee35c:584d326a-d2ac-4d1f-bd52-54c811c6cce80001-01-01T00:00:00HighTitleA compromised access key may permit an adversary to have more access than intended to an Azure Cosmos DB instance UserThreatCategoryElevation of PrivilegesUserThreatShortDescriptionA user subject gains increased capability or privilege by taking advantage of an implementation bugUserThreatDescriptionA compromised access key may permit an adversary to have over-privileged access to an Azure Cosmos DB instance InteractionStringGET Call Record DetailsPossibleMitigationsUse resource (SAS like) tokens (derived using master keys) to connect to Cosmos DB instances whenever possible. Scope the resource tokens to permit only the privileges necessary (e.g. read-only). Store secrets in a secret storage solution (e.g. Azure Key Vault). Refer: <a href="https://aka.ms/tmt-th54">https://aka.ms/tmt-th54</a> PriorityHighSDLPhaseDesignd37480d8-de0a-4967-b94c-81ace2b9f751AutoGenerated584d326a-d2ac-4d1f-bd52-54c811c6cce8TH54falsefalseTH97d37480d8-de0a-4967-b94c-81ace2b9f7514b289fb1-df89-4d9b-8ab7-b90dc071c68b49ad6fdf-78cd-4183-ab77-6a0dce2242745391df34-17a6-4ed9-87af-59d10800f0ee4b289fb1-df89-4d9b-8ab7-b90dc071c68b165d37480d8-de0a-4967-b94c-81ace2b9f751:4b289fb1-df89-4d9b-8ab7-b90dc071c68b:49ad6fdf-78cd-4183-ab77-6a0dce2242740001-01-01T00:00:00HighTitleAn adversary can gain access to sensitive data by performing SQL injection through Web APIUserThreatCategoryTamperingUserThreatShortDescriptionTampering is the act of altering the bits. Tampering with a process involves changing bits in the running process. Similarly, Tampering with a data flow involves changing bits on the wire or between two running processesUserThreatDescriptionSQL injection is an attack in which malicious code is inserted into strings that are later passed to an instance of SQL Server for parsing and execution. The primary form of SQL injection consists of direct insertion of code into user-input variables that are concatenated with SQL commands and executed. A less direct attack injects malicious code into strings that are destined for storage in a table or as metadata. When the stored strings are subsequently concatenated into a dynamic SQL command, the malicious code is executed. InteractionStringGET Call RecordPossibleMitigationsEnsure that type-safe parameters are used in Web API for data access. Refer: <a href="https://aka.ms/tmtinputval#typesafe-api">https://aka.ms/tmtinputval#typesafe-api</a>PriorityHighSDLPhaseImplementationd37480d8-de0a-4967-b94c-81ace2b9f751AutoGenerated49ad6fdf-78cd-4183-ab77-6a0dce224274TH97falsefalseTH108d37480d8-de0a-4967-b94c-81ace2b9f7514b289fb1-df89-4d9b-8ab7-b90dc071c68b49ad6fdf-78cd-4183-ab77-6a0dce2242745391df34-17a6-4ed9-87af-59d10800f0ee4b289fb1-df89-4d9b-8ab7-b90dc071c68b164d37480d8-de0a-4967-b94c-81ace2b9f751:4b289fb1-df89-4d9b-8ab7-b90dc071c68b:49ad6fdf-78cd-4183-ab77-6a0dce2242740001-01-01T00:00:00HighTitleAn adversary may inject malicious inputs into an API and affect downstream processesUserThreatCategoryTamperingUserThreatShortDescriptionTampering is the act of altering the bits. Tampering with a process involves changing bits in the running process. Similarly, Tampering with a data flow involves changing bits on the wire or between two running processesUserThreatDescriptionAn adversary may inject malicious inputs into an API and affect downstream processesInteractionStringGET Call RecordPossibleMitigationsEnsure that model validation is done on Web API methods. Refer: <a href="https://aka.ms/tmtinputval#validation-api">https://aka.ms/tmtinputval#validation-api</a> Implement input validation on all string type parameters accepted by Web API methods. Refer: <a href="https://aka.ms/tmtinputval#string-api">https://aka.ms/tmtinputval#string-api</a>PriorityHighSDLPhaseImplementationd37480d8-de0a-4967-b94c-81ace2b9f751AutoGenerated49ad6fdf-78cd-4183-ab77-6a0dce224274TH108falsefalseTH87d37480d8-de0a-4967-b94c-81ace2b9f7514b289fb1-df89-4d9b-8ab7-b90dc071c68b49ad6fdf-78cd-4183-ab77-6a0dce2242745391df34-17a6-4ed9-87af-59d10800f0ee4b289fb1-df89-4d9b-8ab7-b90dc071c68b163d37480d8-de0a-4967-b94c-81ace2b9f751:4b289fb1-df89-4d9b-8ab7-b90dc071c68b:49ad6fdf-78cd-4183-ab77-6a0dce2242740001-01-01T00:00:00HighTitleAn adversary may spoof Call Record Insights Function App and gain access to Web APIUserThreatCategorySpoofingUserThreatShortDescriptionSpoofing is when a process or entity is something other than its claimed identity. Examples include substituting a process, a file, website or a network addressUserThreatDescriptionIf proper authentication is not in place, an adversary can spoof a source process or external entity and gain unauthorized access to the Web Application InteractionStringGET Call RecordPossibleMitigationsEnsure that standard authentication techniques are used to secure Web APIs. Refer: <a href="https://aka.ms/tmtauthn#authn-secure-api">https://aka.ms/tmtauthn#authn-secure-api</a>PriorityHighSDLPhaseDesignd37480d8-de0a-4967-b94c-81ace2b9f751AutoGenerated49ad6fdf-78cd-4183-ab77-6a0dce224274TH87falsefalseTH109d37480d8-de0a-4967-b94c-81ace2b9f7514b289fb1-df89-4d9b-8ab7-b90dc071c68b49ad6fdf-78cd-4183-ab77-6a0dce2242745391df34-17a6-4ed9-87af-59d10800f0ee4b289fb1-df89-4d9b-8ab7-b90dc071c68b162d37480d8-de0a-4967-b94c-81ace2b9f751:4b289fb1-df89-4d9b-8ab7-b90dc071c68b:49ad6fdf-78cd-4183-ab77-6a0dce2242740001-01-01T00:00:00HighTitleAttacker can deny a malicious act on an API leading to repudiation issuesUserThreatCategoryRepudiationUserThreatShortDescriptionRepudiation threats involve an adversary denying that something happenedUserThreatDescriptionAttacker can deny a malicious act on an API leading to repudiation issuesInteractionStringGET Call RecordPossibleMitigationsEnsure that auditing and logging is enforced on Web API. Refer: <a href="https://aka.ms/tmtauditlog#logging-web-api">https://aka.ms/tmtauditlog#logging-web-api</a>PriorityHighSDLPhaseDesignd37480d8-de0a-4967-b94c-81ace2b9f751AutoGenerated49ad6fdf-78cd-4183-ab77-6a0dce224274TH109falsefalseTH83d37480d8-de0a-4967-b94c-81ace2b9f7514b289fb1-df89-4d9b-8ab7-b90dc071c68b49ad6fdf-78cd-4183-ab77-6a0dce2242745391df34-17a6-4ed9-87af-59d10800f0ee4b289fb1-df89-4d9b-8ab7-b90dc071c68b161d37480d8-de0a-4967-b94c-81ace2b9f751:4b289fb1-df89-4d9b-8ab7-b90dc071c68b:49ad6fdf-78cd-4183-ab77-6a0dce2242740001-01-01T00:00:00MediumTitleAn adversary can gain access to sensitive data stored in Web API's config filesUserThreatCategoryInformation DisclosureUserThreatShortDescriptionInformation disclosure happens when the information can be read by an unauthorized partyUserThreatDescriptionAn adversary can gain access to the config files. and if sensitive data is stored in it, it would be compromised.InteractionStringGET Call RecordPossibleMitigationsEncrypt sections of Web API's configuration files that contain sensitive data. Refer: <a href="https://aka.ms/tmtconfigmgmt#config-sensitive">https://aka.ms/tmtconfigmgmt#config-sensitive</a>PriorityMediumSDLPhaseImplementationd37480d8-de0a-4967-b94c-81ace2b9f751AutoGenerated49ad6fdf-78cd-4183-ab77-6a0dce224274TH83falsefalseTH16d37480d8-de0a-4967-b94c-81ace2b9f7514b289fb1-df89-4d9b-8ab7-b90dc071c68b49ad6fdf-78cd-4183-ab77-6a0dce2242745391df34-17a6-4ed9-87af-59d10800f0ee4b289fb1-df89-4d9b-8ab7-b90dc071c68b160d37480d8-de0a-4967-b94c-81ace2b9f751:4b289fb1-df89-4d9b-8ab7-b90dc071c68b:49ad6fdf-78cd-4183-ab77-6a0dce2242740001-01-01T00:00:00HighTitleAn adversary can gain access to sensitive data by sniffing traffic to Web APIUserThreatCategoryInformation DisclosureUserThreatShortDescriptionInformation disclosure happens when the information can be read by an unauthorized partyUserThreatDescriptionAn adversary can gain access to sensitive data by sniffing traffic to Web APIInteractionStringGET Call RecordPossibleMitigationsForce all traffic to Web APIs over HTTPS connection. Refer: <a href="https://aka.ms/tmtcommsec#webapi-https">https://aka.ms/tmtcommsec#webapi-https</a>PriorityHighSDLPhaseImplementationd37480d8-de0a-4967-b94c-81ace2b9f751AutoGenerated49ad6fdf-78cd-4183-ab77-6a0dce224274TH16falsefalseTH106d37480d8-de0a-4967-b94c-81ace2b9f7514b289fb1-df89-4d9b-8ab7-b90dc071c68b49ad6fdf-78cd-4183-ab77-6a0dce2242745391df34-17a6-4ed9-87af-59d10800f0ee4b289fb1-df89-4d9b-8ab7-b90dc071c68b159d37480d8-de0a-4967-b94c-81ace2b9f751:4b289fb1-df89-4d9b-8ab7-b90dc071c68b:49ad6fdf-78cd-4183-ab77-6a0dce2242740001-01-01T00:00:00HighTitleAn adversary can gain access to sensitive information from an API through error messagesUserThreatCategoryInformation DisclosureUserThreatShortDescriptionInformation disclosure happens when the information can be read by an unauthorized partyUserThreatDescriptionAn adversary can gain access to sensitive data such as the following, through verbose error messages - Server names - Connection strings - Usernames - Passwords - SQL procedures - Details of dynamic SQL failures - Stack trace and lines of code - Variables stored in memory - Drive and folder locations - Application install points - Host configuration settings - Other internal application details InteractionStringGET Call RecordPossibleMitigationsEnsure that proper exception handling is done in ASP.NET Web API. Refer: <a href="https://aka.ms/tmtxmgmt#exception">https://aka.ms/tmtxmgmt#exception</a>PriorityHighSDLPhaseImplementationd37480d8-de0a-4967-b94c-81ace2b9f751AutoGenerated49ad6fdf-78cd-4183-ab77-6a0dce224274TH106falsefalseTH110d37480d8-de0a-4967-b94c-81ace2b9f7514b289fb1-df89-4d9b-8ab7-b90dc071c68b49ad6fdf-78cd-4183-ab77-6a0dce2242745391df34-17a6-4ed9-87af-59d10800f0ee4b289fb1-df89-4d9b-8ab7-b90dc071c68b158d37480d8-de0a-4967-b94c-81ace2b9f751:4b289fb1-df89-4d9b-8ab7-b90dc071c68b:49ad6fdf-78cd-4183-ab77-6a0dce2242740001-01-01T00:00:00HighTitleAn adversary may gain unauthorized access to Web API due to poor access control checksUserThreatCategoryElevation of PrivilegesUserThreatShortDescriptionA user subject gains increased capability or privilege by taking advantage of an implementation bugUserThreatDescriptionAn adversary may gain unauthorized access to Web API due to poor access control checksInteractionStringGET Call RecordPossibleMitigationsImplement proper authorization mechanism in ASP.NET Web API. Refer: <a href="https://aka.ms/tmtauthz#authz-aspnet">https://aka.ms/tmtauthz#authz-aspnet</a>PriorityHighSDLPhaseImplementationd37480d8-de0a-4967-b94c-81ace2b9f751AutoGenerated49ad6fdf-78cd-4183-ab77-6a0dce224274TH110falsefalseTH97d37480d8-de0a-4967-b94c-81ace2b9f7517436eb65-9227-43ae-b7fb-f4a21af156fa49ad6fdf-78cd-4183-ab77-6a0dce2242745391df34-17a6-4ed9-87af-59d10800f0ee7436eb65-9227-43ae-b7fb-f4a21af156fa157d37480d8-de0a-4967-b94c-81ace2b9f751:7436eb65-9227-43ae-b7fb-f4a21af156fa:49ad6fdf-78cd-4183-ab77-6a0dce2242740001-01-01T00:00:00HighTitleAn adversary can gain access to sensitive data by performing SQL injection through Web APIUserThreatCategoryTamperingUserThreatShortDescriptionTampering is the act of altering the bits. Tampering with a process involves changing bits in the running process. Similarly, Tampering with a data flow involves changing bits on the wire or between two running processesUserThreatDescriptionSQL injection is an attack in which malicious code is inserted into strings that are later passed to an instance of SQL Server for parsing and execution. The primary form of SQL injection consists of direct insertion of code into user-input variables that are concatenated with SQL commands and executed. A less direct attack injects malicious code into strings that are destined for storage in a table or as metadata. When the stored strings are subsequently concatenated into a dynamic SQL command, the malicious code is executed. InteractionStringPOST SubscriptionPossibleMitigationsEnsure that type-safe parameters are used in Web API for data access. Refer: <a href="https://aka.ms/tmtinputval#typesafe-api">https://aka.ms/tmtinputval#typesafe-api</a>PriorityHighSDLPhaseImplementationd37480d8-de0a-4967-b94c-81ace2b9f751AutoGenerated49ad6fdf-78cd-4183-ab77-6a0dce224274TH97falsefalseTH108d37480d8-de0a-4967-b94c-81ace2b9f7517436eb65-9227-43ae-b7fb-f4a21af156fa49ad6fdf-78cd-4183-ab77-6a0dce2242745391df34-17a6-4ed9-87af-59d10800f0ee7436eb65-9227-43ae-b7fb-f4a21af156fa156d37480d8-de0a-4967-b94c-81ace2b9f751:7436eb65-9227-43ae-b7fb-f4a21af156fa:49ad6fdf-78cd-4183-ab77-6a0dce2242740001-01-01T00:00:00HighTitleAn adversary may inject malicious inputs into an API and affect downstream processesUserThreatCategoryTamperingUserThreatShortDescriptionTampering is the act of altering the bits. Tampering with a process involves changing bits in the running process. Similarly, Tampering with a data flow involves changing bits on the wire or between two running processesUserThreatDescriptionAn adversary may inject malicious inputs into an API and affect downstream processesInteractionStringPOST SubscriptionPossibleMitigationsEnsure that model validation is done on Web API methods. Refer: <a href="https://aka.ms/tmtinputval#validation-api">https://aka.ms/tmtinputval#validation-api</a> Implement input validation on all string type parameters accepted by Web API methods. Refer: <a href="https://aka.ms/tmtinputval#string-api">https://aka.ms/tmtinputval#string-api</a>PriorityHighSDLPhaseImplementationd37480d8-de0a-4967-b94c-81ace2b9f751AutoGenerated49ad6fdf-78cd-4183-ab77-6a0dce224274TH108falsefalseTH87d37480d8-de0a-4967-b94c-81ace2b9f7517436eb65-9227-43ae-b7fb-f4a21af156fa49ad6fdf-78cd-4183-ab77-6a0dce2242745391df34-17a6-4ed9-87af-59d10800f0ee7436eb65-9227-43ae-b7fb-f4a21af156fa155d37480d8-de0a-4967-b94c-81ace2b9f751:7436eb65-9227-43ae-b7fb-f4a21af156fa:49ad6fdf-78cd-4183-ab77-6a0dce2242740001-01-01T00:00:00HighTitleAn adversary may spoof Call Record Insights Function App and gain access to Web APIUserThreatCategorySpoofingUserThreatShortDescriptionSpoofing is when a process or entity is something other than its claimed identity. Examples include substituting a process, a file, website or a network addressUserThreatDescriptionIf proper authentication is not in place, an adversary can spoof a source process or external entity and gain unauthorized access to the Web Application InteractionStringPOST SubscriptionPossibleMitigationsEnsure that standard authentication techniques are used to secure Web APIs. Refer: <a href="https://aka.ms/tmtauthn#authn-secure-api">https://aka.ms/tmtauthn#authn-secure-api</a>PriorityHighSDLPhaseDesignd37480d8-de0a-4967-b94c-81ace2b9f751AutoGenerated49ad6fdf-78cd-4183-ab77-6a0dce224274TH87falsefalseTH109d37480d8-de0a-4967-b94c-81ace2b9f7517436eb65-9227-43ae-b7fb-f4a21af156fa49ad6fdf-78cd-4183-ab77-6a0dce2242745391df34-17a6-4ed9-87af-59d10800f0ee7436eb65-9227-43ae-b7fb-f4a21af156fa154d37480d8-de0a-4967-b94c-81ace2b9f751:7436eb65-9227-43ae-b7fb-f4a21af156fa:49ad6fdf-78cd-4183-ab77-6a0dce2242740001-01-01T00:00:00HighTitleAttacker can deny a malicious act on an API leading to repudiation issuesUserThreatCategoryRepudiationUserThreatShortDescriptionRepudiation threats involve an adversary denying that something happenedUserThreatDescriptionAttacker can deny a malicious act on an API leading to repudiation issuesInteractionStringPOST SubscriptionPossibleMitigationsEnsure that auditing and logging is enforced on Web API. Refer: <a href="https://aka.ms/tmtauditlog#logging-web-api">https://aka.ms/tmtauditlog#logging-web-api</a>PriorityHighSDLPhaseDesignd37480d8-de0a-4967-b94c-81ace2b9f751AutoGenerated49ad6fdf-78cd-4183-ab77-6a0dce224274TH109falsefalseTH83d37480d8-de0a-4967-b94c-81ace2b9f7517436eb65-9227-43ae-b7fb-f4a21af156fa49ad6fdf-78cd-4183-ab77-6a0dce2242745391df34-17a6-4ed9-87af-59d10800f0ee7436eb65-9227-43ae-b7fb-f4a21af156fa153d37480d8-de0a-4967-b94c-81ace2b9f751:7436eb65-9227-43ae-b7fb-f4a21af156fa:49ad6fdf-78cd-4183-ab77-6a0dce2242740001-01-01T00:00:00MediumTitleAn adversary can gain access to sensitive data stored in Web API's config filesUserThreatCategoryInformation DisclosureUserThreatShortDescriptionInformation disclosure happens when the information can be read by an unauthorized partyUserThreatDescriptionAn adversary can gain access to the config files. and if sensitive data is stored in it, it would be compromised.InteractionStringPOST SubscriptionPossibleMitigationsEncrypt sections of Web API's configuration files that contain sensitive data. Refer: <a href="https://aka.ms/tmtconfigmgmt#config-sensitive">https://aka.ms/tmtconfigmgmt#config-sensitive</a>PriorityMediumSDLPhaseImplementationd37480d8-de0a-4967-b94c-81ace2b9f751AutoGenerated49ad6fdf-78cd-4183-ab77-6a0dce224274TH83falsefalseTH16d37480d8-de0a-4967-b94c-81ace2b9f7517436eb65-9227-43ae-b7fb-f4a21af156fa49ad6fdf-78cd-4183-ab77-6a0dce2242745391df34-17a6-4ed9-87af-59d10800f0ee7436eb65-9227-43ae-b7fb-f4a21af156fa152d37480d8-de0a-4967-b94c-81ace2b9f751:7436eb65-9227-43ae-b7fb-f4a21af156fa:49ad6fdf-78cd-4183-ab77-6a0dce2242740001-01-01T00:00:00HighTitleAn adversary can gain access to sensitive data by sniffing traffic to Web APIUserThreatCategoryInformation DisclosureUserThreatShortDescriptionInformation disclosure happens when the information can be read by an unauthorized partyUserThreatDescriptionAn adversary can gain access to sensitive data by sniffing traffic to Web APIInteractionStringPOST SubscriptionPossibleMitigationsForce all traffic to Web APIs over HTTPS connection. Refer: <a href="https://aka.ms/tmtcommsec#webapi-https">https://aka.ms/tmtcommsec#webapi-https</a>PriorityHighSDLPhaseImplementationd37480d8-de0a-4967-b94c-81ace2b9f751AutoGenerated49ad6fdf-78cd-4183-ab77-6a0dce224274TH16falsefalseTH106d37480d8-de0a-4967-b94c-81ace2b9f7517436eb65-9227-43ae-b7fb-f4a21af156fa49ad6fdf-78cd-4183-ab77-6a0dce2242745391df34-17a6-4ed9-87af-59d10800f0ee7436eb65-9227-43ae-b7fb-f4a21af156fa151d37480d8-de0a-4967-b94c-81ace2b9f751:7436eb65-9227-43ae-b7fb-f4a21af156fa:49ad6fdf-78cd-4183-ab77-6a0dce2242740001-01-01T00:00:00HighTitleAn adversary can gain access to sensitive information from an API through error messagesUserThreatCategoryInformation DisclosureUserThreatShortDescriptionInformation disclosure happens when the information can be read by an unauthorized partyUserThreatDescriptionAn adversary can gain access to sensitive data such as the following, through verbose error messages - Server names - Connection strings - Usernames - Passwords - SQL procedures - Details of dynamic SQL failures - Stack trace and lines of code - Variables stored in memory - Drive and folder locations - Application install points - Host configuration settings - Other internal application details InteractionStringPOST SubscriptionPossibleMitigationsEnsure that proper exception handling is done in ASP.NET Web API. Refer: <a href="https://aka.ms/tmtxmgmt#exception">https://aka.ms/tmtxmgmt#exception</a>PriorityHighSDLPhaseImplementationd37480d8-de0a-4967-b94c-81ace2b9f751AutoGenerated49ad6fdf-78cd-4183-ab77-6a0dce224274TH106falsefalseTH110d37480d8-de0a-4967-b94c-81ace2b9f7517436eb65-9227-43ae-b7fb-f4a21af156fa49ad6fdf-78cd-4183-ab77-6a0dce2242745391df34-17a6-4ed9-87af-59d10800f0ee7436eb65-9227-43ae-b7fb-f4a21af156fa150d37480d8-de0a-4967-b94c-81ace2b9f751:7436eb65-9227-43ae-b7fb-f4a21af156fa:49ad6fdf-78cd-4183-ab77-6a0dce2242740001-01-01T00:00:00HighTitleAn adversary may gain unauthorized access to Web API due to poor access control checksUserThreatCategoryElevation of PrivilegesUserThreatShortDescriptionA user subject gains increased capability or privilege by taking advantage of an implementation bugUserThreatDescriptionAn adversary may gain unauthorized access to Web API due to poor access control checksInteractionStringPOST SubscriptionPossibleMitigationsImplement proper authorization mechanism in ASP.NET Web API. Refer: <a href="https://aka.ms/tmtauthz#authz-aspnet">https://aka.ms/tmtauthz#authz-aspnet</a>PriorityHighSDLPhaseImplementationd37480d8-de0a-4967-b94c-81ace2b9f751AutoGenerated49ad6fdf-78cd-4183-ab77-6a0dce224274TH110falsefalseTH110d37480d8-de0a-4967-b94c-81ace2b9f751b29d6184-ede8-447d-9e35-d418fff6ce5049ad6fdf-78cd-4183-ab77-6a0dce2242745391df34-17a6-4ed9-87af-59d10800f0eeb29d6184-ede8-447d-9e35-d418fff6ce5075d37480d8-de0a-4967-b94c-81ace2b9f751:b29d6184-ede8-447d-9e35-d418fff6ce50:49ad6fdf-78cd-4183-ab77-6a0dce2242740001-01-01T00:00:00HighTitleAn adversary may gain unauthorized access to Web API due to poor access control checksUserThreatCategoryElevation of PrivilegesUserThreatShortDescriptionA user subject gains increased capability or privilege by taking advantage of an implementation bugUserThreatDescriptionAn adversary may gain unauthorized access to Web API due to poor access control checksInteractionStringGET Subscription RequestPossibleMitigationsImplement proper authorization mechanism in ASP.NET Web API. Refer: <a href="https://aka.ms/tmtauthz#authz-aspnet">https://aka.ms/tmtauthz#authz-aspnet</a>PriorityHighSDLPhaseImplementationd37480d8-de0a-4967-b94c-81ace2b9f751AutoGenerated49ad6fdf-78cd-4183-ab77-6a0dce224274TH110falsefalseTH106d37480d8-de0a-4967-b94c-81ace2b9f751b29d6184-ede8-447d-9e35-d418fff6ce5049ad6fdf-78cd-4183-ab77-6a0dce2242745391df34-17a6-4ed9-87af-59d10800f0eeb29d6184-ede8-447d-9e35-d418fff6ce5076d37480d8-de0a-4967-b94c-81ace2b9f751:b29d6184-ede8-447d-9e35-d418fff6ce50:49ad6fdf-78cd-4183-ab77-6a0dce2242740001-01-01T00:00:00HighTitleAn adversary can gain access to sensitive information from an API through error messagesUserThreatCategoryInformation DisclosureUserThreatShortDescriptionInformation disclosure happens when the information can be read by an unauthorized partyUserThreatDescriptionAn adversary can gain access to sensitive data such as the following, through verbose error messages - Server names - Connection strings - Usernames - Passwords - SQL procedures - Details of dynamic SQL failures - Stack trace and lines of code - Variables stored in memory - Drive and folder locations - Application install points - Host configuration settings - Other internal application details InteractionStringGET Subscription RequestPossibleMitigationsEnsure that proper exception handling is done in ASP.NET Web API. Refer: <a href="https://aka.ms/tmtxmgmt#exception">https://aka.ms/tmtxmgmt#exception</a>PriorityHighSDLPhaseImplementationd37480d8-de0a-4967-b94c-81ace2b9f751AutoGenerated49ad6fdf-78cd-4183-ab77-6a0dce224274TH106falsefalseTH16d37480d8-de0a-4967-b94c-81ace2b9f751b29d6184-ede8-447d-9e35-d418fff6ce5049ad6fdf-78cd-4183-ab77-6a0dce2242745391df34-17a6-4ed9-87af-59d10800f0eeb29d6184-ede8-447d-9e35-d418fff6ce5077d37480d8-de0a-4967-b94c-81ace2b9f751:b29d6184-ede8-447d-9e35-d418fff6ce50:49ad6fdf-78cd-4183-ab77-6a0dce2242740001-01-01T00:00:00HighTitleAn adversary can gain access to sensitive data by sniffing traffic to Web APIUserThreatCategoryInformation DisclosureUserThreatShortDescriptionInformation disclosure happens when the information can be read by an unauthorized partyUserThreatDescriptionAn adversary can gain access to sensitive data by sniffing traffic to Web APIInteractionStringGET Subscription RequestPossibleMitigationsForce all traffic to Web APIs over HTTPS connection. Refer: <a href="https://aka.ms/tmtcommsec#webapi-https">https://aka.ms/tmtcommsec#webapi-https</a>PriorityHighSDLPhaseImplementationd37480d8-de0a-4967-b94c-81ace2b9f751AutoGenerated49ad6fdf-78cd-4183-ab77-6a0dce224274TH16falsefalseTH83d37480d8-de0a-4967-b94c-81ace2b9f751b29d6184-ede8-447d-9e35-d418fff6ce5049ad6fdf-78cd-4183-ab77-6a0dce2242745391df34-17a6-4ed9-87af-59d10800f0eeb29d6184-ede8-447d-9e35-d418fff6ce5078d37480d8-de0a-4967-b94c-81ace2b9f751:b29d6184-ede8-447d-9e35-d418fff6ce50:49ad6fdf-78cd-4183-ab77-6a0dce2242740001-01-01T00:00:00MediumTitleAn adversary can gain access to sensitive data stored in Web API's config filesUserThreatCategoryInformation DisclosureUserThreatShortDescriptionInformation disclosure happens when the information can be read by an unauthorized partyUserThreatDescriptionAn adversary can gain access to the config files. and if sensitive data is stored in it, it would be compromised.InteractionStringGET Subscription RequestPossibleMitigationsEncrypt sections of Web API's configuration files that contain sensitive data. Refer: <a href="https://aka.ms/tmtconfigmgmt#config-sensitive">https://aka.ms/tmtconfigmgmt#config-sensitive</a>PriorityMediumSDLPhaseImplementationd37480d8-de0a-4967-b94c-81ace2b9f751AutoGenerated49ad6fdf-78cd-4183-ab77-6a0dce224274TH83falsefalseTH109d37480d8-de0a-4967-b94c-81ace2b9f751b29d6184-ede8-447d-9e35-d418fff6ce5049ad6fdf-78cd-4183-ab77-6a0dce2242745391df34-17a6-4ed9-87af-59d10800f0eeb29d6184-ede8-447d-9e35-d418fff6ce5079d37480d8-de0a-4967-b94c-81ace2b9f751:b29d6184-ede8-447d-9e35-d418fff6ce50:49ad6fdf-78cd-4183-ab77-6a0dce2242740001-01-01T00:00:00HighTitleAttacker can deny a malicious act on an API leading to repudiation issuesUserThreatCategoryRepudiationUserThreatShortDescriptionRepudiation threats involve an adversary denying that something happenedUserThreatDescriptionAttacker can deny a malicious act on an API leading to repudiation issuesInteractionStringGET Subscription RequestPossibleMitigationsEnsure that auditing and logging is enforced on Web API. Refer: <a href="https://aka.ms/tmtauditlog#logging-web-api">https://aka.ms/tmtauditlog#logging-web-api</a>PriorityHighSDLPhaseDesignd37480d8-de0a-4967-b94c-81ace2b9f751AutoGenerated49ad6fdf-78cd-4183-ab77-6a0dce224274TH109falsefalseTH87d37480d8-de0a-4967-b94c-81ace2b9f751b29d6184-ede8-447d-9e35-d418fff6ce5049ad6fdf-78cd-4183-ab77-6a0dce2242745391df34-17a6-4ed9-87af-59d10800f0eeb29d6184-ede8-447d-9e35-d418fff6ce5080d37480d8-de0a-4967-b94c-81ace2b9f751:b29d6184-ede8-447d-9e35-d418fff6ce50:49ad6fdf-78cd-4183-ab77-6a0dce2242740001-01-01T00:00:00HighTitleAn adversary may spoof Call Record Insights Function App and gain access to Web APIUserThreatCategorySpoofingUserThreatShortDescriptionSpoofing is when a process or entity is something other than its claimed identity. Examples include substituting a process, a file, website or a network addressUserThreatDescriptionIf proper authentication is not in place, an adversary can spoof a source process or external entity and gain unauthorized access to the Web Application InteractionStringGET Subscription RequestPossibleMitigationsEnsure that standard authentication techniques are used to secure Web APIs. Refer: <a href="https://aka.ms/tmtauthn#authn-secure-api">https://aka.ms/tmtauthn#authn-secure-api</a>PriorityHighSDLPhaseDesignd37480d8-de0a-4967-b94c-81ace2b9f751AutoGenerated49ad6fdf-78cd-4183-ab77-6a0dce224274TH87falsefalseTH108d37480d8-de0a-4967-b94c-81ace2b9f751b29d6184-ede8-447d-9e35-d418fff6ce5049ad6fdf-78cd-4183-ab77-6a0dce2242745391df34-17a6-4ed9-87af-59d10800f0eeb29d6184-ede8-447d-9e35-d418fff6ce5081d37480d8-de0a-4967-b94c-81ace2b9f751:b29d6184-ede8-447d-9e35-d418fff6ce50:49ad6fdf-78cd-4183-ab77-6a0dce2242740001-01-01T00:00:00HighTitleAn adversary may inject malicious inputs into an API and affect downstream processesUserThreatCategoryTamperingUserThreatShortDescriptionTampering is the act of altering the bits. Tampering with a process involves changing bits in the running process. Similarly, Tampering with a data flow involves changing bits on the wire or between two running processesUserThreatDescriptionAn adversary may inject malicious inputs into an API and affect downstream processesInteractionStringGET Subscription RequestPossibleMitigationsEnsure that model validation is done on Web API methods. Refer: <a href="https://aka.ms/tmtinputval#validation-api">https://aka.ms/tmtinputval#validation-api</a> Implement input validation on all string type parameters accepted by Web API methods. Refer: <a href="https://aka.ms/tmtinputval#string-api">https://aka.ms/tmtinputval#string-api</a>PriorityHighSDLPhaseImplementationd37480d8-de0a-4967-b94c-81ace2b9f751AutoGenerated49ad6fdf-78cd-4183-ab77-6a0dce224274TH108falsefalseTH97d37480d8-de0a-4967-b94c-81ace2b9f751b29d6184-ede8-447d-9e35-d418fff6ce5049ad6fdf-78cd-4183-ab77-6a0dce2242745391df34-17a6-4ed9-87af-59d10800f0eeb29d6184-ede8-447d-9e35-d418fff6ce5082d37480d8-de0a-4967-b94c-81ace2b9f751:b29d6184-ede8-447d-9e35-d418fff6ce50:49ad6fdf-78cd-4183-ab77-6a0dce2242740001-01-01T00:00:00HighTitleAn adversary can gain access to sensitive data by performing SQL injection through Web APIUserThreatCategoryTamperingUserThreatShortDescriptionTampering is the act of altering the bits. Tampering with a process involves changing bits in the running process. Similarly, Tampering with a data flow involves changing bits on the wire or between two running processesUserThreatDescriptionSQL injection is an attack in which malicious code is inserted into strings that are later passed to an instance of SQL Server for parsing and execution. The primary form of SQL injection consists of direct insertion of code into user-input variables that are concatenated with SQL commands and executed. A less direct attack injects malicious code into strings that are destined for storage in a table or as metadata. When the stored strings are subsequently concatenated into a dynamic SQL command, the malicious code is executed. InteractionStringGET Subscription RequestPossibleMitigationsEnsure that type-safe parameters are used in Web API for data access. Refer: <a href="https://aka.ms/tmtinputval#typesafe-api">https://aka.ms/tmtinputval#typesafe-api</a>PriorityHighSDLPhaseImplementationd37480d8-de0a-4967-b94c-81ace2b9f751AutoGenerated49ad6fdf-78cd-4183-ab77-6a0dce224274TH97falsefalseTH5949ad6fdf-78cd-4183-ab77-6a0dce224274b97bb647-8252-4b35-ac83-00263906b232fe7b81cf-2ab3-4eb1-ac05-29576b1002dd5391df34-17a6-4ed9-87af-59d10800f0eeb97bb647-8252-4b35-ac83-00263906b2328349ad6fdf-78cd-4183-ab77-6a0dce224274:b97bb647-8252-4b35-ac83-00263906b232:fe7b81cf-2ab3-4eb1-ac05-29576b1002dd0001-01-01T00:00:00HighTitleAn adversary may exploit the permissions provisioned to the device token to gain elevated privilegesUserThreatCategoryElevation of PrivilegesUserThreatShortDescriptionA user subject gains increased capability or privilege by taking advantage of an implementation bugUserThreatDescriptionAn adversary may leverage insufficient authorization checks on the Event Hub (SAS token) and be able to listen (Read) to the Events and manage (change) configurations of the Event HubInteractionStringGraph Event Notification PublishingPossibleMitigationsUse a send-only permissions SAS Key for generating device tokens. Refer: <a href="https://aka.ms/tmtauthz#sendonly-sas">https://aka.ms/tmtauthz#sendonly-sas</a>PriorityHighSDLPhaseDesign49ad6fdf-78cd-4183-ab77-6a0dce224274AutoGeneratedfe7b81cf-2ab3-4eb1-ac05-29576b1002ddTH59falsefalseTH6049ad6fdf-78cd-4183-ab77-6a0dce224274b97bb647-8252-4b35-ac83-00263906b232fe7b81cf-2ab3-4eb1-ac05-29576b1002dd5391df34-17a6-4ed9-87af-59d10800f0eeb97bb647-8252-4b35-ac83-00263906b2328449ad6fdf-78cd-4183-ab77-6a0dce224274:b97bb647-8252-4b35-ac83-00263906b232:fe7b81cf-2ab3-4eb1-ac05-29576b1002dd0001-01-01T00:00:00HighTitleAn adversary bypass the secure functionalities of the Event Hub if devices authenticate with tokens that give direct access to Event HubUserThreatCategoryElevation of PrivilegesUserThreatShortDescriptionA user subject gains increased capability or privilege by taking advantage of an implementation bugUserThreatDescriptionIf a token that grants direct access to the event hub is given to the device, it would be able to send messages directly to the eventhub without being subjected to throttling. It further exempts such a device from being able to be blacklisted.InteractionStringGraph Event Notification PublishingPossibleMitigationsDo not use access tokens that provide direct access to the Event Hub. Refer: <a href="https://aka.ms/tmtauthz#access-tokens-hub">https://aka.ms/tmtauthz#access-tokens-hub</a>PriorityHighSDLPhaseDesign49ad6fdf-78cd-4183-ab77-6a0dce224274AutoGeneratedfe7b81cf-2ab3-4eb1-ac05-29576b1002ddTH60falsefalseTH6249ad6fdf-78cd-4183-ab77-6a0dce224274b97bb647-8252-4b35-ac83-00263906b232fe7b81cf-2ab3-4eb1-ac05-29576b1002dd5391df34-17a6-4ed9-87af-59d10800f0eeb97bb647-8252-4b35-ac83-00263906b2328549ad6fdf-78cd-4183-ab77-6a0dce224274:b97bb647-8252-4b35-ac83-00263906b232:fe7b81cf-2ab3-4eb1-ac05-29576b1002dd0001-01-01T00:00:00HighTitleAn adversary may gain elevated privileges on Event HubUserThreatCategoryElevation of PrivilegesUserThreatShortDescriptionA user subject gains increased capability or privilege by taking advantage of an implementation bugUserThreatDescriptionAn adversary may gain elevated privileges on the functionality of Event Hub if SAS keys with over-privileged permissions are used to connectInteractionStringGraph Event Notification PublishingPossibleMitigationsConnect to Event Hub using SAS keys that have the minimum permissions required. Refer: <a href="https://aka.ms/tmtauthz#sas-minimum-permissions">https://aka.ms/tmtauthz#sas-minimum-permissions</a>PriorityHighSDLPhaseDesign49ad6fdf-78cd-4183-ab77-6a0dce224274AutoGeneratedfe7b81cf-2ab3-4eb1-ac05-29576b1002ddTH62falsefalseTH5849ad6fdf-78cd-4183-ab77-6a0dce224274b97bb647-8252-4b35-ac83-00263906b232fe7b81cf-2ab3-4eb1-ac05-29576b1002dd5391df34-17a6-4ed9-87af-59d10800f0eeb97bb647-8252-4b35-ac83-00263906b2328649ad6fdf-78cd-4183-ab77-6a0dce224274:b97bb647-8252-4b35-ac83-00263906b232:fe7b81cf-2ab3-4eb1-ac05-29576b1002dd0001-01-01T00:00:00HighTitleAn adversary may spoof a device by reusing the authentication tokens of one device in anotherUserThreatCategorySpoofingUserThreatShortDescriptionSpoofing is when a process or entity is something other than its claimed identity. Examples include substituting a process, a file, website or a network addressUserThreatDescriptionIf multiple devices use the same SaS token, then an adversary can spoof any device using a token that he or she has access toInteractionStringGraph Event Notification PublishingPossibleMitigationsUse per device authentication credentials using SaS tokens. Refer: <a href="https://aka.ms/tmtauthn#authn-sas-tokens">https://aka.ms/tmtauthn#authn-sas-tokens</a>PriorityHighSDLPhaseImplementation49ad6fdf-78cd-4183-ab77-6a0dce224274AutoGeneratedfe7b81cf-2ab3-4eb1-ac05-29576b1002ddTH58falsefalseTH6149ad6fdf-78cd-4183-ab77-6a0dce224274b97bb647-8252-4b35-ac83-00263906b232fe7b81cf-2ab3-4eb1-ac05-29576b1002dd5391df34-17a6-4ed9-87af-59d10800f0eeb97bb647-8252-4b35-ac83-00263906b2328749ad6fdf-78cd-4183-ab77-6a0dce224274:b97bb647-8252-4b35-ac83-00263906b232:fe7b81cf-2ab3-4eb1-ac05-29576b1002dd0001-01-01T00:00:00HighTitleAn adversary may eavesdrop the communication between the a client and Event HubUserThreatCategoryTamperingUserThreatShortDescriptionTampering is the act of altering the bits. Tampering with a process involves changing bits in the running process. Similarly, Tampering with a data flow involves changing bits on the wire or between two running processesUserThreatDescriptionAn adversary may eavesdrop and interfere with the communication between a client and Event Hub and possibly tamper the data that is transmittedInteractionStringGraph Event Notification PublishingPossibleMitigationsSecure communication to Event Hub using SSL/TLS. Refer: <a href="https://aka.ms/tmtcommsec#comm-ssltls">https://aka.ms/tmtcommsec#comm-ssltls</a>PriorityHighSDLPhaseDesign49ad6fdf-78cd-4183-ab77-6a0dce224274AutoGeneratedfe7b81cf-2ab3-4eb1-ac05-29576b1002ddTH61falsefalseTH17949ad6fdf-78cd-4183-ab77-6a0dce2242741d40d609-61a9-491f-9f3e-4c2f01d7e51869fb8454-6039-49f5-a97c-bbacdedbc1df5391df34-17a6-4ed9-87af-59d10800f0ee1d40d609-61a9-491f-9f3e-4c2f01d7e5188849ad6fdf-78cd-4183-ab77-6a0dce224274:1d40d609-61a9-491f-9f3e-4c2f01d7e518:69fb8454-6039-49f5-a97c-bbacdedbc1df0001-01-01T00:00:00HighTitleAn adversary can gain unauthorized access to Azure Key Vault instances due to weak network security configuration.UserThreatCategoryElevation of PrivilegesUserThreatShortDescriptionA user subject gains increased capability or privilege by taking advantage of an implementation bugUserThreatDescriptionAn adversary can gain unauthorized access to Azure Key Vault instances due to weak network security configuration.InteractionStringGET Event Hub ConnectionStringPossibleMitigationsRestrict access to Azure Key Vault instances by configuring firewall rules to permit connections from selected networks (e.g. a virtual network or a custom set of IP addresses).For Key Vault client applications behind a firewall trying to access a Key Vault instance, see best practices mentioned here: <a href="https://aka.ms/tmt-th179 ">https://aka.ms/tmt-th179 </a>PriorityHighSDLPhaseImplementation49ad6fdf-78cd-4183-ab77-6a0dce224274AutoGenerated69fb8454-6039-49f5-a97c-bbacdedbc1dfTH179falsefalseTH18149ad6fdf-78cd-4183-ab77-6a0dce2242741d40d609-61a9-491f-9f3e-4c2f01d7e51869fb8454-6039-49f5-a97c-bbacdedbc1df5391df34-17a6-4ed9-87af-59d10800f0ee1d40d609-61a9-491f-9f3e-4c2f01d7e5188949ad6fdf-78cd-4183-ab77-6a0dce224274:1d40d609-61a9-491f-9f3e-4c2f01d7e518:69fb8454-6039-49f5-a97c-bbacdedbc1df0001-01-01T00:00:00HighTitleAn adversary may gain unauthorized access to manage Azure Key Vault due to weak authorization rules.UserThreatCategoryElevation of PrivilegesUserThreatShortDescriptionA user subject gains increased capability or privilege by taking advantage of an implementation bugUserThreatDescriptionAn adversary may gain unauthorized access to manage Azure Key Vault due to weak authorization rules. InteractionStringGET Event Hub ConnectionStringPossibleMitigationsAccess to the Azure Key Vault management plane should be restricted by choosing appropriate Role-Based Access Control (RBAC) roles and privileges in accordance with the principle of least privilege. Over permissive or weak authorization rules may potentially permit data plane access (e.g. a user with Contribute (RBAC) permissions to Key Vault management plane may grant themselves access to the data plane by setting the Azure Key Vault access policy). Refer : <a href="https://aka.ms/tmt-th181 ">https://aka.ms/tmt-th181 </a>PriorityHighSDLPhaseImplementation49ad6fdf-78cd-4183-ab77-6a0dce224274AutoGenerated69fb8454-6039-49f5-a97c-bbacdedbc1dfTH181falsefalseTH18249ad6fdf-78cd-4183-ab77-6a0dce2242741d40d609-61a9-491f-9f3e-4c2f01d7e51869fb8454-6039-49f5-a97c-bbacdedbc1df5391df34-17a6-4ed9-87af-59d10800f0ee1d40d609-61a9-491f-9f3e-4c2f01d7e5189049ad6fdf-78cd-4183-ab77-6a0dce224274:1d40d609-61a9-491f-9f3e-4c2f01d7e518:69fb8454-6039-49f5-a97c-bbacdedbc1df0001-01-01T00:00:00HighTitleAn adversary may gain unauthorized access to Azure Key Vault secrets due to weak authorization rulesUserThreatCategoryElevation of PrivilegesUserThreatShortDescriptionA user subject gains increased capability or privilege by taking advantage of an implementation bugUserThreatDescriptionAn adversary may gain unauthorized access to Azure Key Vault secrets due to weak authorization rules InteractionStringGET Event Hub ConnectionStringPossibleMitigationsLimit Azure Key Vault data plane access by configuring strict access policies. Grant users, groups and applications the ability to perform only the necessary operations against keys or secrets in a Key Vault instance. Follow the principle of least privilege and grant privileges only as needed. Refer : <a href="https://aka.ms/tmt-th181 ">https://aka.ms/tmt-th181 </a>PriorityHighSDLPhaseImplementation49ad6fdf-78cd-4183-ab77-6a0dce224274AutoGenerated69fb8454-6039-49f5-a97c-bbacdedbc1dfTH182falsefalseTH18649ad6fdf-78cd-4183-ab77-6a0dce2242741d40d609-61a9-491f-9f3e-4c2f01d7e51869fb8454-6039-49f5-a97c-bbacdedbc1df5391df34-17a6-4ed9-87af-59d10800f0ee1d40d609-61a9-491f-9f3e-4c2f01d7e5189149ad6fdf-78cd-4183-ab77-6a0dce224274:1d40d609-61a9-491f-9f3e-4c2f01d7e518:69fb8454-6039-49f5-a97c-bbacdedbc1df0001-01-01T00:00:00LowTitleAn adversary may attempt to delete key vault or key vault object causing business disruption. UserThreatCategoryDenial of ServiceUserThreatShortDescriptionDenial of Service happens when the process or a datastore is not able to service incoming requests or perform up to specUserThreatDescriptionAn adversary may attempt to delete key vault or key vault object causing business disruption. InteractionStringGET Event Hub ConnectionStringPossibleMitigationsKey Vault's soft delete feature allows recovery of the deleted vaults and vault objects, known as soft-delete . Soft deleted resources are retained for a set period of time, 90 days. Refer : <a href="https://aka.ms/tmt-th186 ">https://aka.ms/tmt-th186 </a>PriorityLowSDLPhaseImplementation49ad6fdf-78cd-4183-ab77-6a0dce224274AutoGenerated69fb8454-6039-49f5-a97c-bbacdedbc1dfTH186falsefalseTH179d37480d8-de0a-4967-b94c-81ace2b9f751b89a5c49-b2ce-4da4-9dc4-a0c40c18dcd369fb8454-6039-49f5-a97c-bbacdedbc1df5391df34-17a6-4ed9-87af-59d10800f0eeb89a5c49-b2ce-4da4-9dc4-a0c40c18dcd3113d37480d8-de0a-4967-b94c-81ace2b9f751:b89a5c49-b2ce-4da4-9dc4-a0c40c18dcd3:69fb8454-6039-49f5-a97c-bbacdedbc1df0001-01-01T00:00:00HighTitleAn adversary can gain unauthorized access to Azure Key Vault instances due to weak network security configuration.UserThreatCategoryElevation of PrivilegesUserThreatShortDescriptionA user subject gains increased capability or privilege by taking advantage of an implementation bugUserThreatDescriptionAn adversary can gain unauthorized access to Azure Key Vault instances due to weak network security configuration.InteractionStringKey Vault Secret ManagementPossibleMitigationsRestrict access to Azure Key Vault instances by configuring firewall rules to permit connections from selected networks (e.g. a virtual network or a custom set of IP addresses).For Key Vault client applications behind a firewall trying to access a Key Vault instance, see best practices mentioned here: <a href="https://aka.ms/tmt-th179 ">https://aka.ms/tmt-th179 </a>PriorityHighSDLPhaseImplementationd37480d8-de0a-4967-b94c-81ace2b9f751AutoGenerated69fb8454-6039-49f5-a97c-bbacdedbc1dfTH179falsefalseTH181d37480d8-de0a-4967-b94c-81ace2b9f751b89a5c49-b2ce-4da4-9dc4-a0c40c18dcd369fb8454-6039-49f5-a97c-bbacdedbc1df5391df34-17a6-4ed9-87af-59d10800f0eeb89a5c49-b2ce-4da4-9dc4-a0c40c18dcd3114d37480d8-de0a-4967-b94c-81ace2b9f751:b89a5c49-b2ce-4da4-9dc4-a0c40c18dcd3:69fb8454-6039-49f5-a97c-bbacdedbc1df0001-01-01T00:00:00HighTitleAn adversary may gain unauthorized access to manage Azure Key Vault due to weak authorization rules.UserThreatCategoryElevation of PrivilegesUserThreatShortDescriptionA user subject gains increased capability or privilege by taking advantage of an implementation bugUserThreatDescriptionAn adversary may gain unauthorized access to manage Azure Key Vault due to weak authorization rules. InteractionStringKey Vault Secret ManagementPossibleMitigationsAccess to the Azure Key Vault management plane should be restricted by choosing appropriate Role-Based Access Control (RBAC) roles and privileges in accordance with the principle of least privilege. Over permissive or weak authorization rules may potentially permit data plane access (e.g. a user with Contribute (RBAC) permissions to Key Vault management plane may grant themselves access to the data plane by setting the Azure Key Vault access policy). Refer : <a href="https://aka.ms/tmt-th181 ">https://aka.ms/tmt-th181 </a>PriorityHighSDLPhaseImplementationd37480d8-de0a-4967-b94c-81ace2b9f751AutoGenerated69fb8454-6039-49f5-a97c-bbacdedbc1dfTH181falsefalseTH182d37480d8-de0a-4967-b94c-81ace2b9f751b89a5c49-b2ce-4da4-9dc4-a0c40c18dcd369fb8454-6039-49f5-a97c-bbacdedbc1df5391df34-17a6-4ed9-87af-59d10800f0eeb89a5c49-b2ce-4da4-9dc4-a0c40c18dcd3115d37480d8-de0a-4967-b94c-81ace2b9f751:b89a5c49-b2ce-4da4-9dc4-a0c40c18dcd3:69fb8454-6039-49f5-a97c-bbacdedbc1df0001-01-01T00:00:00HighTitleAn adversary may gain unauthorized access to Azure Key Vault secrets due to weak authorization rulesUserThreatCategoryElevation of PrivilegesUserThreatShortDescriptionA user subject gains increased capability or privilege by taking advantage of an implementation bugUserThreatDescriptionAn adversary may gain unauthorized access to Azure Key Vault secrets due to weak authorization rules InteractionStringKey Vault Secret ManagementPossibleMitigationsLimit Azure Key Vault data plane access by configuring strict access policies. Grant users, groups and applications the ability to perform only the necessary operations against keys or secrets in a Key Vault instance. Follow the principle of least privilege and grant privileges only as needed. Refer : <a href="https://aka.ms/tmt-th181 ">https://aka.ms/tmt-th181 </a>PriorityHighSDLPhaseImplementationd37480d8-de0a-4967-b94c-81ace2b9f751AutoGenerated69fb8454-6039-49f5-a97c-bbacdedbc1dfTH182falsefalseTH186d37480d8-de0a-4967-b94c-81ace2b9f751b89a5c49-b2ce-4da4-9dc4-a0c40c18dcd369fb8454-6039-49f5-a97c-bbacdedbc1df5391df34-17a6-4ed9-87af-59d10800f0eeb89a5c49-b2ce-4da4-9dc4-a0c40c18dcd3116d37480d8-de0a-4967-b94c-81ace2b9f751:b89a5c49-b2ce-4da4-9dc4-a0c40c18dcd3:69fb8454-6039-49f5-a97c-bbacdedbc1df0001-01-01T00:00:00LowTitleAn adversary may attempt to delete key vault or key vault object causing business disruption. UserThreatCategoryDenial of ServiceUserThreatShortDescriptionDenial of Service happens when the process or a datastore is not able to service incoming requests or perform up to specUserThreatDescriptionAn adversary may attempt to delete key vault or key vault object causing business disruption. InteractionStringKey Vault Secret ManagementPossibleMitigationsKey Vault's soft delete feature allows recovery of the deleted vaults and vault objects, known as soft-delete . Soft deleted resources are retained for a set period of time, 90 days. Refer : <a href="https://aka.ms/tmt-th186 ">https://aka.ms/tmt-th186 </a>PriorityLowSDLPhaseImplementationd37480d8-de0a-4967-b94c-81ace2b9f751AutoGenerated69fb8454-6039-49f5-a97c-bbacdedbc1dfTH186falsefalseTH3087952830-0247-4d6d-b43e-3e2f46f47ed0970a9b10-b72f-4409-8a0f-9365579d7853d37480d8-de0a-4967-b94c-81ace2b9f7515391df34-17a6-4ed9-87af-59d10800f0ee970a9b10-b72f-4409-8a0f-9365579d785317587952830-0247-4d6d-b43e-3e2f46f47ed0:970a9b10-b72f-4409-8a0f-9365579d7853:d37480d8-de0a-4967-b94c-81ace2b9f7510001-01-01T00:00:00MediumTitleAttacker can deny the malicious act and remove the attack foot prints leading to repudiation issuesUserThreatCategoryRepudiationUserThreatShortDescriptionRepudiation threats involve an adversary denying that something happenedUserThreatDescriptionProper logging of all security events and user actions builds traceability in a system and denies any possible repudiation issues. In the absence of proper auditing and logging controls, it would become impossible to implement any accountability in a systemInteractionStringGET Health StatePossibleMitigationsEnsure that auditing and logging is enforced on the application. Refer: <a href="https://aka.ms/tmtauditlog#auditing">https://aka.ms/tmtauditlog#auditing</a> Ensure that log rotation and separation are in place. Refer: <a href="https://aka.ms/tmtauditlog#log-rotation">https://aka.ms/tmtauditlog#log-rotation</a> Ensure that Audit and Log Files have Restricted Access. Refer: <a href="https://aka.ms/tmtauditlog#log-restricted-access">https://aka.ms/tmtauditlog#log-restricted-access</a> Ensure that User Management Events are Logged. Refer: <a href="https://aka.ms/tmtauditlog#user-management">https://aka.ms/tmtauditlog#user-management</a>PriorityMediumSDLPhaseImplementation87952830-0247-4d6d-b43e-3e2f46f47ed0AutoGeneratedd37480d8-de0a-4967-b94c-81ace2b9f751TH30falsefalseTH9987952830-0247-4d6d-b43e-3e2f46f47ed0970a9b10-b72f-4409-8a0f-9365579d7853d37480d8-de0a-4967-b94c-81ace2b9f7515391df34-17a6-4ed9-87af-59d10800f0ee970a9b10-b72f-4409-8a0f-9365579d785317487952830-0247-4d6d-b43e-3e2f46f47ed0:970a9b10-b72f-4409-8a0f-9365579d7853:d37480d8-de0a-4967-b94c-81ace2b9f7510001-01-01T00:00:00HighTitleAn adversary may gain access to sensitive data from uncleared browser cacheUserThreatCategoryInformation DisclosureUserThreatShortDescriptionInformation disclosure happens when the information can be read by an unauthorized partyUserThreatDescriptionAn adversary may gain access to sensitive data from uncleared browser cacheInteractionStringGET Health StatePossibleMitigationsEnsure that sensitive content is not cached on the browser. Refer: <a href="https://aka.ms/tmtdata#cache-browser">https://aka.ms/tmtdata#cache-browser</a>PriorityHighSDLPhaseImplementation87952830-0247-4d6d-b43e-3e2f46f47ed0AutoGeneratedd37480d8-de0a-4967-b94c-81ace2b9f751TH99falsefalseTH9487952830-0247-4d6d-b43e-3e2f46f47ed0970a9b10-b72f-4409-8a0f-9365579d7853d37480d8-de0a-4967-b94c-81ace2b9f7515391df34-17a6-4ed9-87af-59d10800f0ee970a9b10-b72f-4409-8a0f-9365579d785317387952830-0247-4d6d-b43e-3e2f46f47ed0:970a9b10-b72f-4409-8a0f-9365579d7853:d37480d8-de0a-4967-b94c-81ace2b9f7510001-01-01T00:00:00HighTitleAn adversary can gain access to sensitive information through error messagesUserThreatCategoryInformation DisclosureUserThreatShortDescriptionInformation disclosure happens when the information can be read by an unauthorized partyUserThreatDescriptionAn adversary can gain access to sensitive data such as the following, through verbose error messages - Server names - Connection strings - Usernames - Passwords - SQL procedures - Details of dynamic SQL failures - Stack trace and lines of code - Variables stored in memory - Drive and folder locations - Application install points - Host configuration settings - Other internal application details InteractionStringGET Health StatePossibleMitigationsDo not expose security details in error messages. Refer: <a href="https://aka.ms/tmtxmgmt#messages">https://aka.ms/tmtxmgmt#messages</a> Implement Default error handling page. Refer: <a href="https://aka.ms/tmtxmgmt#default">https://aka.ms/tmtxmgmt#default</a> Set Deployment Method to Retail in IIS. Refer: <a href="https://aka.ms/tmtxmgmt#deployment">https://aka.ms/tmtxmgmt#deployment</a> Exceptions should fail safely. Refer: <a href="https://aka.ms/tmtxmgmt#fail">https://aka.ms/tmtxmgmt#fail</a> ASP.NET applications must disable tracing and debugging prior to deployment. Refer: <a href="https://aka.ms/tmtconfigmgmt#trace-deploy">https://aka.ms/tmtconfigmgmt#trace-deploy</a> Implement controls to prevent username enumeration. Refer: <a href="https://aka.ms/tmtauthn#controls-username-enum">https://aka.ms/tmtauthn#controls-username-enum</a>PriorityHighSDLPhaseImplementation87952830-0247-4d6d-b43e-3e2f46f47ed0AutoGeneratedd37480d8-de0a-4967-b94c-81ace2b9f751TH94falsefalseTH987952830-0247-4d6d-b43e-3e2f46f47ed0970a9b10-b72f-4409-8a0f-9365579d7853d37480d8-de0a-4967-b94c-81ace2b9f7515391df34-17a6-4ed9-87af-59d10800f0ee970a9b10-b72f-4409-8a0f-9365579d785317287952830-0247-4d6d-b43e-3e2f46f47ed0:970a9b10-b72f-4409-8a0f-9365579d7853:d37480d8-de0a-4967-b94c-81ace2b9f7510001-01-01T00:00:00HighTitleAn adversary can gain access to sensitive data by sniffing traffic to Web ApplicationUserThreatCategoryInformation DisclosureUserThreatShortDescriptionInformation disclosure happens when the information can be read by an unauthorized partyUserThreatDescriptionAn adversary may conduct man in the middle attack and downgrade TLS connection to clear text protocol, or forcing browser communication to pass through a proxy server that he controls. This may happen because the application may use mixed content or HTTP Strict Transport Security policy is not ensured.InteractionStringGET Health StatePossibleMitigationsApplications available over HTTPS must use secure cookies. Refer: <a href="https://aka.ms/tmtsmgmt#https-secure-cookies">https://aka.ms/tmtsmgmt#https-secure-cookies</a> Enable HTTP Strict Transport Security (HSTS). Refer: <a href="https://aka.ms/tmtcommsec#http-hsts">https://aka.ms/tmtcommsec#http-hsts</a>PriorityHighSDLPhaseImplementation87952830-0247-4d6d-b43e-3e2f46f47ed0AutoGeneratedd37480d8-de0a-4967-b94c-81ace2b9f751TH9falsefalseTH8087952830-0247-4d6d-b43e-3e2f46f47ed0970a9b10-b72f-4409-8a0f-9365579d7853d37480d8-de0a-4967-b94c-81ace2b9f7515391df34-17a6-4ed9-87af-59d10800f0ee970a9b10-b72f-4409-8a0f-9365579d785317187952830-0247-4d6d-b43e-3e2f46f47ed0:970a9b10-b72f-4409-8a0f-9365579d7853:d37480d8-de0a-4967-b94c-81ace2b9f7510001-01-01T00:00:00MediumTitleAn adversary can gain access to certain pages or the site as a whole.UserThreatCategoryInformation DisclosureUserThreatShortDescriptionInformation disclosure happens when the information can be read by an unauthorized partyUserThreatDescriptionRobots.txt is often found in your site's root directory and exists to regulate the bots that crawl your site. This is where you can grant or deny permission to all or some specific search engine robots to access certain pages or your site as a whole. The standard for this file was developed in 1994 and is known as the Robots Exclusion Standard or Robots Exclusion Protocol. Detailed info about the robots.txt protocol can be found at robotstxt.org.InteractionStringGET Health StatePossibleMitigationsEnsure that administrative interfaces are appropriately locked down. Refer: <a href="https://aka.ms/tmtauthn#admin-interface-lockdown">https://aka.ms/tmtauthn#admin-interface-lockdown</a>PriorityMediumSDLPhaseImplementation87952830-0247-4d6d-b43e-3e2f46f47ed0AutoGeneratedd37480d8-de0a-4967-b94c-81ace2b9f751TH80falsefalseTH55d37480d8-de0a-4967-b94c-81ace2b9f751f1bf866c-8df5-4944-bad7-9d23b80ed08c584d326a-d2ac-4d1f-bd52-54c811c6cce85391df34-17a6-4ed9-87af-59d10800f0eef1bf866c-8df5-4944-bad7-9d23b80ed08c149d37480d8-de0a-4967-b94c-81ace2b9f751:f1bf866c-8df5-4944-bad7-9d23b80ed08c:584d326a-d2ac-4d1f-bd52-54c811c6cce80001-01-01T00:00:00HighTitleAn adversary may reuse a stolen long-lived resource token, access key or connection string to access an Azure Cosmos DB instanceUserThreatCategoryElevation of PrivilegesUserThreatShortDescriptionA user subject gains increased capability or privilege by taking advantage of an implementation bugUserThreatDescriptionAn adversary may reuse a stolen long-lived resource token, access key or connection string to access an Azure Cosmos DB instanceInteractionStringUPSERT Call Record DetailsPossibleMitigationsUse minimum token lifetimes for generated resource tokens. Rotate secrets (e.g. resource tokens, access keys and passwords in connection strings) frequently, in accordance with your organization's policies. Refer: <a href="https://aka.ms/tmt-th55">https://aka.ms/tmt-th55</a>PriorityHighSDLPhaseImplementationd37480d8-de0a-4967-b94c-81ace2b9f751AutoGenerated584d326a-d2ac-4d1f-bd52-54c811c6cce8TH55falsefalseTH53d37480d8-de0a-4967-b94c-81ace2b9f751f1bf866c-8df5-4944-bad7-9d23b80ed08c584d326a-d2ac-4d1f-bd52-54c811c6cce85391df34-17a6-4ed9-87af-59d10800f0eef1bf866c-8df5-4944-bad7-9d23b80ed08c148d37480d8-de0a-4967-b94c-81ace2b9f751:f1bf866c-8df5-4944-bad7-9d23b80ed08c:584d326a-d2ac-4d1f-bd52-54c811c6cce80001-01-01T00:00:00HighTitleAn adversary having access to Azure Cosmos DB may read sensitive clear-text dataUserThreatCategoryInformation DisclosureUserThreatShortDescriptionInformation disclosure happens when the information can be read by an unauthorized partyUserThreatDescriptionAn adversary having access to Azure Cosmos DB may read sensitive clear-text dataInteractionStringUPSERT Call Record DetailsPossibleMitigationsEncrypt sensitive data before storing it in Azure Document DB.PriorityHighSDLPhaseDesignd37480d8-de0a-4967-b94c-81ace2b9f751AutoGenerated584d326a-d2ac-4d1f-bd52-54c811c6cce8TH53falsefalseTH57d37480d8-de0a-4967-b94c-81ace2b9f751f1bf866c-8df5-4944-bad7-9d23b80ed08c584d326a-d2ac-4d1f-bd52-54c811c6cce85391df34-17a6-4ed9-87af-59d10800f0eef1bf866c-8df5-4944-bad7-9d23b80ed08c147d37480d8-de0a-4967-b94c-81ace2b9f751:f1bf866c-8df5-4944-bad7-9d23b80ed08c:584d326a-d2ac-4d1f-bd52-54c811c6cce80001-01-01T00:00:00HighTitleAn adversary can gain unauthorized access to Azure Cosmos DB instances due to weak network security configurationUserThreatCategoryElevation of PrivilegesUserThreatShortDescriptionA user subject gains increased capability or privilege by taking advantage of an implementation bugUserThreatDescriptionAn adversary can gain unauthorized access to Azure Cosmos DB instances due to weak network security configurationInteractionStringUPSERT Call Record DetailsPossibleMitigationsRestrict access to Azure Cosmos DB instances by configuring account-level firewall rules to only permit connections from selected IP addresses where possible. Refer: <a href="https://aka.ms/tmt-th57">https://aka.ms/tmt-th57</a>PriorityHighSDLPhaseImplementationd37480d8-de0a-4967-b94c-81ace2b9f751AutoGenerated584d326a-d2ac-4d1f-bd52-54c811c6cce8TH57falsefalseTH56d37480d8-de0a-4967-b94c-81ace2b9f751f1bf866c-8df5-4944-bad7-9d23b80ed08c584d326a-d2ac-4d1f-bd52-54c811c6cce85391df34-17a6-4ed9-87af-59d10800f0eef1bf866c-8df5-4944-bad7-9d23b80ed08c146d37480d8-de0a-4967-b94c-81ace2b9f751:f1bf866c-8df5-4944-bad7-9d23b80ed08c:584d326a-d2ac-4d1f-bd52-54c811c6cce80001-01-01T00:00:00HighTitleAn adversary may read content stored in Azure Cosmos DB instances through SQL injection based attacksUserThreatCategoryInformation DisclosureUserThreatShortDescriptionInformation disclosure happens when the information can be read by an unauthorized partyUserThreatDescriptionAn adversary may read content stored in Azure Cosmos DB instances through SQL injection based attacksInteractionStringUPSERT Call Record DetailsPossibleMitigationsUse parametrized SQL queries to query Cosmos DB instances. Refer: <a href="https://aka.ms/tmt-th56">https://aka.ms/tmt-th56</a>PriorityHighSDLPhaseImplementationd37480d8-de0a-4967-b94c-81ace2b9f751AutoGenerated584d326a-d2ac-4d1f-bd52-54c811c6cce8TH56falsefalseTH54d37480d8-de0a-4967-b94c-81ace2b9f751f1bf866c-8df5-4944-bad7-9d23b80ed08c584d326a-d2ac-4d1f-bd52-54c811c6cce85391df34-17a6-4ed9-87af-59d10800f0eef1bf866c-8df5-4944-bad7-9d23b80ed08c145d37480d8-de0a-4967-b94c-81ace2b9f751:f1bf866c-8df5-4944-bad7-9d23b80ed08c:584d326a-d2ac-4d1f-bd52-54c811c6cce80001-01-01T00:00:00HighTitleA compromised access key may permit an adversary to have more access than intended to an Azure Cosmos DB instance UserThreatCategoryElevation of PrivilegesUserThreatShortDescriptionA user subject gains increased capability or privilege by taking advantage of an implementation bugUserThreatDescriptionA compromised access key may permit an adversary to have over-privileged access to an Azure Cosmos DB instance InteractionStringUPSERT Call Record DetailsPossibleMitigationsUse resource (SAS like) tokens (derived using master keys) to connect to Cosmos DB instances whenever possible. Scope the resource tokens to permit only the privileges necessary (e.g. read-only). Store secrets in a secret storage solution (e.g. Azure Key Vault). Refer: <a href="https://aka.ms/tmt-th54">https://aka.ms/tmt-th54</a> PriorityHighSDLPhaseDesignd37480d8-de0a-4967-b94c-81ace2b9f751AutoGenerated584d326a-d2ac-4d1f-bd52-54c811c6cce8TH54falsefalseTH2487952830-0247-4d6d-b43e-3e2f46f47ed0970a9b10-b72f-4409-8a0f-9365579d7853d37480d8-de0a-4967-b94c-81ace2b9f7515391df34-17a6-4ed9-87af-59d10800f0ee970a9b10-b72f-4409-8a0f-9365579d785318387952830-0247-4d6d-b43e-3e2f46f47ed0:970a9b10-b72f-4409-8a0f-9365579d7853:d37480d8-de0a-4967-b94c-81ace2b9f7510001-01-01T00:00:00HighTitleAn adversary can deface the target web application by injecting malicious code or uploading dangerous filesUserThreatCategoryTamperingUserThreatShortDescriptionTampering is the act of altering the bits. Tampering with a process involves changing bits in the running process. Similarly, Tampering with a data flow involves changing bits on the wire or between two running processesUserThreatDescriptionWebsite defacement is an attack on a website where the attacker changes the visual appearance of the site or a webpage. InteractionStringGET Health StatePossibleMitigationsImplement Content Security Policy (CSP), and disable inline javascript. Refer: <a href="https://aka.ms/tmtconfigmgmt#csp-js">https://aka.ms/tmtconfigmgmt#csp-js</a> Enable browser's XSS filter. Refer: <a href="https://aka.ms/tmtconfigmgmt#xss-filter">https://aka.ms/tmtconfigmgmt#xss-filter</a> Access third party javascripts from trusted sources only. Refer: <a href="https://aka.ms/tmtconfigmgmt#js-trusted">https://aka.ms/tmtconfigmgmt#js-trusted</a> Enable ValidateRequest attribute on ASP.NET Pages. Refer: <a href="https://aka.ms/tmtconfigmgmt#validate-aspnet">https://aka.ms/tmtconfigmgmt#validate-aspnet</a> Ensure that each page that could contain user controllable content opts out of automatic MIME sniffing . Refer: <a href="https://aka.ms/tmtinputval#out-sniffing">https://aka.ms/tmtinputval#out-sniffing</a> Use locally-hosted latest versions of JavaScript libraries . Refer: <a href="https://aka.ms/tmtconfigmgmt#local-js">https://aka.ms/tmtconfigmgmt#local-js</a> Ensure appropriate controls are in place when accepting files from users. Refer: <a href="https://aka.ms/tmtinputval#controls-users">https://aka.ms/tmtinputval#controls-users</a> Disable automatic MIME sniffing. Refer: <a href="https://aka.ms/tmtconfigmgmt#mime-sniff">https://aka.ms/tmtconfigmgmt#mime-sniff</a> Encode untrusted web output prior to rendering. Refer: <a href="https://aka.ms/tmtinputval#rendering">https://aka.ms/tmtinputval#rendering</a> Perform input validation and filtering on all string type Model properties. Refer: <a href="https://aka.ms/tmtinputval#typemodel">https://aka.ms/tmtinputval#typemodel</a> Ensure that the system has inbuilt defences against misuse. Refer: <a href="https://aka.ms/tmtauditlog#inbuilt-defenses">https://aka.ms/tmtauditlog#inbuilt-defenses</a> Enable HTTP Strict Transport Security (HSTS). Refer: <a href="https://aka.ms/tmtcommsec#http-hsts">https://aka.ms/tmtcommsec#http-hsts</a> Implement input validation on all string type parameters accepted by Controller methods. Refer: <a href="https://aka.ms/tmtinputval#string-method">https://aka.ms/tmtinputval#string-method</a> Avoid using Html.Raw in Razor views. Refer: <a href="https://aka.ms/tmtinputval#html-razor">https://aka.ms/tmtinputval#html-razor</a> Sanitization should be applied on form fields that accept all characters e.g, rich text editor . Refer: <a href="https://aka.ms/tmtinputval#richtext">https://aka.ms/tmtinputval#richtext</a> Do not assign DOM elements to sinks that do not have inbuilt encoding . Refer: <a href="https://aka.ms/tmtinputval#inbuilt-encode">https://aka.ms/tmtinputval#inbuilt-encode</a>PriorityHighSDLPhaseImplementation87952830-0247-4d6d-b43e-3e2f46f47ed0AutoGeneratedd37480d8-de0a-4967-b94c-81ace2b9f751TH24falsefalseTH8687952830-0247-4d6d-b43e-3e2f46f47ed0970a9b10-b72f-4409-8a0f-9365579d7853d37480d8-de0a-4967-b94c-81ace2b9f7515391df34-17a6-4ed9-87af-59d10800f0ee970a9b10-b72f-4409-8a0f-9365579d785318287952830-0247-4d6d-b43e-3e2f46f47ed0:970a9b10-b72f-4409-8a0f-9365579d7853:d37480d8-de0a-4967-b94c-81ace2b9f7510001-01-01T00:00:00HighTitleAn adversary may spoof Browser and gain access to Web ApplicationUserThreatCategorySpoofingUserThreatShortDescriptionSpoofing is when a process or entity is something other than its claimed identity. Examples include substituting a process, a file, website or a network addressUserThreatDescriptionIf proper authentication is not in place, an adversary can spoof a source process or external entity and gain unauthorized access to the Web ApplicationInteractionStringGET Health StatePossibleMitigationsConsider using a standard authentication mechanism to authenticate to Web Application. Refer: <a href="https://aka.ms/tmtauthn#standard-authn-web-app">https://aka.ms/tmtauthn#standard-authn-web-app</a>PriorityHighSDLPhaseDesign87952830-0247-4d6d-b43e-3e2f46f47ed0AutoGeneratedd37480d8-de0a-4967-b94c-81ace2b9f751TH86falsefalseTH8187952830-0247-4d6d-b43e-3e2f46f47ed0970a9b10-b72f-4409-8a0f-9365579d7853d37480d8-de0a-4967-b94c-81ace2b9f7515391df34-17a6-4ed9-87af-59d10800f0ee970a9b10-b72f-4409-8a0f-9365579d785318187952830-0247-4d6d-b43e-3e2f46f47ed0:970a9b10-b72f-4409-8a0f-9365579d7853:d37480d8-de0a-4967-b94c-81ace2b9f7510001-01-01T00:00:00HighTitleAn adversary can create a fake website and launch phishing attacksUserThreatCategorySpoofingUserThreatShortDescriptionSpoofing is when a process or entity is something other than its claimed identity. Examples include substituting a process, a file, website or a network addressUserThreatDescriptionPhishing is attempted to obtain sensitive information such as usernames, passwords, and credit card details (and sometimes, indirectly, money), often for malicious reasons, by masquerading as a Web Server which is a trustworthy entity in electronic communicationInteractionStringGET Health StatePossibleMitigationsVerify X.509 certificates used to authenticate SSL, TLS, and DTLS connections. Refer: <a href="https://aka.ms/tmtcommsec#x509-ssltls">https://aka.ms/tmtcommsec#x509-ssltls</a> Ensure that authenticated ASP.NET pages incorporate UI Redressing or clickjacking defences. Refer: <a href="https://aka.ms/tmtconfigmgmt#ui-defenses">https://aka.ms/tmtconfigmgmt#ui-defenses</a> Validate all redirects within the application are closed or done safely. Refer: <a href="https://aka.ms/tmtinputval#redirect-safe">https://aka.ms/tmtinputval#redirect-safe</a>PriorityHighSDLPhaseImplementation87952830-0247-4d6d-b43e-3e2f46f47ed0AutoGeneratedd37480d8-de0a-4967-b94c-81ace2b9f751TH81falsefalseTH887952830-0247-4d6d-b43e-3e2f46f47ed0970a9b10-b72f-4409-8a0f-9365579d7853d37480d8-de0a-4967-b94c-81ace2b9f7515391df34-17a6-4ed9-87af-59d10800f0ee970a9b10-b72f-4409-8a0f-9365579d785318087952830-0247-4d6d-b43e-3e2f46f47ed0:970a9b10-b72f-4409-8a0f-9365579d7853:d37480d8-de0a-4967-b94c-81ace2b9f7510001-01-01T00:00:00HighTitleAttackers can steal user session cookies due to insecure cookie attributesUserThreatCategorySpoofingUserThreatShortDescriptionSpoofing is when a process or entity is something other than its claimed identity. Examples include substituting a process, a file, website or a network addressUserThreatDescriptionThe session cookies is the identifier by which the server knows the identity of current user for each incoming request. If the attacker is able to steal the user token he would be able to access all user data and perform all actions on behalf of user. InteractionStringGET Health StatePossibleMitigationsApplications available over HTTPS must use secure cookies. Refer: <a href="https://aka.ms/tmtsmgmt#https-secure-cookies">https://aka.ms/tmtsmgmt#https-secure-cookies</a> All http based application should specify http only for cookie definition. Refer: <a href="https://aka.ms/tmtsmgmt#cookie-definition">https://aka.ms/tmtsmgmt#cookie-definition</a>PriorityHighSDLPhaseImplementation87952830-0247-4d6d-b43e-3e2f46f47ed0AutoGeneratedd37480d8-de0a-4967-b94c-81ace2b9f751TH8falsefalseTH787952830-0247-4d6d-b43e-3e2f46f47ed0970a9b10-b72f-4409-8a0f-9365579d7853d37480d8-de0a-4967-b94c-81ace2b9f7515391df34-17a6-4ed9-87af-59d10800f0ee970a9b10-b72f-4409-8a0f-9365579d785317987952830-0247-4d6d-b43e-3e2f46f47ed0:970a9b10-b72f-4409-8a0f-9365579d7853:d37480d8-de0a-4967-b94c-81ace2b9f7510001-01-01T00:00:00HighTitleAn adversary can steal sensitive data like user credentialsUserThreatCategorySpoofingUserThreatShortDescriptionSpoofing is when a process or entity is something other than its claimed identity. Examples include substituting a process, a file, website or a network addressUserThreatDescriptionAttackers can exploit weaknesses in system to steal user credentials. Downstream and upstream components are often accessed by using credentials stored in configuration stores. Attackers may steal the upstream or downstream component credentials. Attackers may steal credentials if, Credentials are stored and sent in clear text, Weak input validation coupled with dynamic sql queries, Password retrieval mechanism are poor, InteractionStringGET Health StatePossibleMitigationsExplicitly disable the autocomplete HTML attribute in sensitive forms and inputs. Refer: <a href="https://aka.ms/tmtdata#autocomplete-input">https://aka.ms/tmtdata#autocomplete-input</a> Perform input validation and filtering on all string type Model properties. Refer: <a href="https://aka.ms/tmtinputval#typemodel">https://aka.ms/tmtinputval#typemodel</a> Validate all redirects within the application are closed or done safely. Refer: <a href="https://aka.ms/tmtinputval#redirect-safe">https://aka.ms/tmtinputval#redirect-safe</a> Enable step up or adaptive authentication. Refer: <a href="https://aka.ms/tmtauthn#step-up-adaptive-authn">https://aka.ms/tmtauthn#step-up-adaptive-authn</a> Implement forgot password functionalities securely. Refer: <a href="https://aka.ms/tmtauthn#forgot-pword-fxn">https://aka.ms/tmtauthn#forgot-pword-fxn</a> Ensure that password and account policy are implemented. Refer: <a href="https://aka.ms/tmtauthn#pword-account-policy">https://aka.ms/tmtauthn#pword-account-policy</a> Implement input validation on all string type parameters accepted by Controller methods. Refer: <a href="https://aka.ms/tmtinputval#string-method">https://aka.ms/tmtinputval#string-method</a>PriorityHighSDLPhaseImplementation87952830-0247-4d6d-b43e-3e2f46f47ed0AutoGeneratedd37480d8-de0a-4967-b94c-81ace2b9f751TH7falsefalseTH3287952830-0247-4d6d-b43e-3e2f46f47ed0970a9b10-b72f-4409-8a0f-9365579d7853d37480d8-de0a-4967-b94c-81ace2b9f7515391df34-17a6-4ed9-87af-59d10800f0ee970a9b10-b72f-4409-8a0f-9365579d785317887952830-0247-4d6d-b43e-3e2f46f47ed0:970a9b10-b72f-4409-8a0f-9365579d7853:d37480d8-de0a-4967-b94c-81ace2b9f7510001-01-01T00:00:00HighTitleAn adversary can spoof the target web application due to insecure TLS certificate configurationUserThreatCategorySpoofingUserThreatShortDescriptionSpoofing is when a process or entity is something other than its claimed identity. Examples include substituting a process, a file, website or a network addressUserThreatDescriptionEnsure that TLS certificate parameters are configured with correct valuesInteractionStringGET Health StatePossibleMitigationsVerify X.509 certificates used to authenticate SSL, TLS, and DTLS connections. Refer: <a href="https://aka.ms/tmtcommsec#x509-ssltls">https://aka.ms/tmtcommsec#x509-ssltls</a>PriorityHighSDLPhaseImplementation87952830-0247-4d6d-b43e-3e2f46f47ed0AutoGeneratedd37480d8-de0a-4967-b94c-81ace2b9f751TH32falsefalseTH2387952830-0247-4d6d-b43e-3e2f46f47ed0970a9b10-b72f-4409-8a0f-9365579d7853d37480d8-de0a-4967-b94c-81ace2b9f7515391df34-17a6-4ed9-87af-59d10800f0ee970a9b10-b72f-4409-8a0f-9365579d785317787952830-0247-4d6d-b43e-3e2f46f47ed0:970a9b10-b72f-4409-8a0f-9365579d7853:d37480d8-de0a-4967-b94c-81ace2b9f7510001-01-01T00:00:00HighTitleAn adversary can get access to a user's session due to insecure coding practicesUserThreatCategorySpoofingUserThreatShortDescriptionSpoofing is when a process or entity is something other than its claimed identity. Examples include substituting a process, a file, website or a network addressUserThreatDescriptionThe session cookies is the identifier by which the server knows the identity of current user for each incoming request. If the attacker is able to steal the user token he would be able to access all user data and perform all actions on behalf of user.InteractionStringGET Health StatePossibleMitigationsEnable ValidateRequest attribute on ASP.NET Pages. Refer: <a href="https://aka.ms/tmtconfigmgmt#validate-aspnet">https://aka.ms/tmtconfigmgmt#validate-aspnet</a> Encode untrusted web output prior to rendering. Refer: <a href="https://aka.ms/tmtinputval#rendering">https://aka.ms/tmtinputval#rendering</a> Avoid using Html.Raw in Razor views. Refer: <a href="https://aka.ms/tmtinputval#html-razor">https://aka.ms/tmtinputval#html-razor</a> Sanitization should be applied on form fields that accept all characters e.g, rich text editor . Refer: <a href="https://aka.ms/tmtinputval#richtext">https://aka.ms/tmtinputval#richtext</a> Do not assign DOM elements to sinks that do not have inbuilt encoding . Refer: <a href="https://aka.ms/tmtinputval#inbuilt-encode">https://aka.ms/tmtinputval#inbuilt-encode</a>PriorityHighSDLPhaseImplementation87952830-0247-4d6d-b43e-3e2f46f47ed0AutoGeneratedd37480d8-de0a-4967-b94c-81ace2b9f751TH23falsefalseTH2287952830-0247-4d6d-b43e-3e2f46f47ed0970a9b10-b72f-4409-8a0f-9365579d7853d37480d8-de0a-4967-b94c-81ace2b9f7515391df34-17a6-4ed9-87af-59d10800f0ee970a9b10-b72f-4409-8a0f-9365579d785317687952830-0247-4d6d-b43e-3e2f46f47ed0:970a9b10-b72f-4409-8a0f-9365579d7853:d37480d8-de0a-4967-b94c-81ace2b9f7510001-01-01T00:00:00HighTitleAn adversary can get access to a user's session due to improper logout and timeoutUserThreatCategorySpoofingUserThreatShortDescriptionSpoofing is when a process or entity is something other than its claimed identity. Examples include substituting a process, a file, website or a network addressUserThreatDescriptionThe session cookies is the identifier by which the server knows the identity of current user for each incoming request. If the attacker is able to steal the user token he would be able to access all user data and perform all actions on behalf of user.InteractionStringGET Health StatePossibleMitigationsSet up session for inactivity lifetime. Refer: <a href="https://aka.ms/tmtsmgmt#inactivity-lifetime">https://aka.ms/tmtsmgmt#inactivity-lifetime</a> Implement proper logout from the application. Refer: <a href="https://aka.ms/tmtsmgmt#proper-app-logout">https://aka.ms/tmtsmgmt#proper-app-logout</a>PriorityHighSDLPhaseImplementation87952830-0247-4d6d-b43e-3e2f46f47ed0AutoGeneratedd37480d8-de0a-4967-b94c-81ace2b9f751TH22falsefalseTH3387952830-0247-4d6d-b43e-3e2f46f47ed0970a9b10-b72f-4409-8a0f-9365579d7853d37480d8-de0a-4967-b94c-81ace2b9f7515391df34-17a6-4ed9-87af-59d10800f0ee970a9b10-b72f-4409-8a0f-9365579d785318487952830-0247-4d6d-b43e-3e2f46f47ed0:970a9b10-b72f-4409-8a0f-9365579d7853:d37480d8-de0a-4967-b94c-81ace2b9f7510001-01-01T00:00:00HighTitleAn attacker steals messages off the network and replays them in order to steal a user's sessionUserThreatCategoryTamperingUserThreatShortDescriptionTampering is the act of altering the bits. Tampering with a process involves changing bits in the running process. Similarly, Tampering with a data flow involves changing bits on the wire or between two running processesUserThreatDescriptionAn attacker steals messages off the network and replays them in order to steal a user's sessionInteractionStringGET Health StatePriorityHighSDLPhaseImplementation87952830-0247-4d6d-b43e-3e2f46f47ed0AutoGeneratedd37480d8-de0a-4967-b94c-81ace2b9f751TH33falsefalseTH9687952830-0247-4d6d-b43e-3e2f46f47ed0970a9b10-b72f-4409-8a0f-9365579d7853d37480d8-de0a-4967-b94c-81ace2b9f7515391df34-17a6-4ed9-87af-59d10800f0ee970a9b10-b72f-4409-8a0f-9365579d785318587952830-0247-4d6d-b43e-3e2f46f47ed0:970a9b10-b72f-4409-8a0f-9365579d7853:d37480d8-de0a-4967-b94c-81ace2b9f7510001-01-01T00:00:00HighTitleAn adversary can gain access to sensitive data by performing SQL injection through Web AppUserThreatCategoryTamperingUserThreatShortDescriptionTampering is the act of altering the bits. Tampering with a process involves changing bits in the running process. Similarly, Tampering with a data flow involves changing bits on the wire or between two running processesUserThreatDescriptionSQL injection is an attack in which malicious code is inserted into strings that are later passed to an instance of SQL Server for parsing and execution. The primary form of SQL injection consists of direct insertion of code into user-input variables that are concatenated with SQL commands and executed. A less direct attack injects malicious code into strings that are destined for storage in a table or as metadata. When the stored strings are subsequently concatenated into a dynamic SQL command, the malicious code is executed. InteractionStringGET Health StatePossibleMitigationsEnsure that type-safe parameters are used in Web Application for data access. Refer: <a href="https://aka.ms/tmtinputval#typesafe">https://aka.ms/tmtinputval#typesafe</a>PriorityHighSDLPhaseImplementation87952830-0247-4d6d-b43e-3e2f46f47ed0AutoGeneratedd37480d8-de0a-4967-b94c-81ace2b9f751TH96falsefalseTH9887952830-0247-4d6d-b43e-3e2f46f47ed0970a9b10-b72f-4409-8a0f-9365579d7853d37480d8-de0a-4967-b94c-81ace2b9f7515391df34-17a6-4ed9-87af-59d10800f0ee970a9b10-b72f-4409-8a0f-9365579d785318687952830-0247-4d6d-b43e-3e2f46f47ed0:970a9b10-b72f-4409-8a0f-9365579d7853:d37480d8-de0a-4967-b94c-81ace2b9f7510001-01-01T00:00:00HighTitleAn adversary can gain access to sensitive data stored in Web App's config filesUserThreatCategoryTamperingUserThreatShortDescriptionTampering is the act of altering the bits. Tampering with a process involves changing bits in the running process. Similarly, Tampering with a data flow involves changing bits on the wire or between two running processesUserThreatDescriptionAn adversary can gain access to the config files. and if sensitive data is stored in it, it would be compromised.InteractionStringGET Health StatePossibleMitigationsEncrypt sections of Web App's configuration files that contain sensitive data. Refer: <a href="https://aka.ms/tmtdata#encrypt-data">https://aka.ms/tmtdata#encrypt-data</a>PriorityHighSDLPhaseImplementation87952830-0247-4d6d-b43e-3e2f46f47ed0AutoGeneratedd37480d8-de0a-4967-b94c-81ace2b9f751TH98falsefalseTH91d37480d8-de0a-4967-b94c-81ace2b9f7518708f0cc-7157-441c-b430-d69e15ec1ab9432e06ef-869b-4816-b0b1-6964d81fb3e55391df34-17a6-4ed9-87af-59d10800f0ee8708f0cc-7157-441c-b430-d69e15ec1ab9187d37480d8-de0a-4967-b94c-81ace2b9f751:8708f0cc-7157-441c-b430-d69e15ec1ab9:432e06ef-869b-4816-b0b1-6964d81fb3e50001-01-01T00:00:00HighTitleAn adversary can leverage the weak scalability of token cache and cause DoSUserThreatCategoryDenial of ServiceUserThreatShortDescriptionDenial of Service happens when the process or a datastore is not able to service incoming requests or perform up to specUserThreatDescriptionThe default cache that ADAL (Active Directory Authentication Library) uses is an in-memory cache that relies on a static store, available process-wide. While this works for native applications, it does not scale for mid tier and backend applications. This can cause availability issues and result in denial of service either by the influence of an adversary or by the large scale of application's users.InteractionStringGET OpenId-ConfigurationPossibleMitigationsOverride the default ADAL token cache with a scalable alternative. Refer: <a href="https://aka.ms/tmtauthn#adal-scalable">https://aka.ms/tmtauthn#adal-scalable</a>PriorityHighSDLPhaseDesignd37480d8-de0a-4967-b94c-81ace2b9f751AutoGenerated432e06ef-869b-4816-b0b1-6964d81fb3e5TH91falsefalseTH11d37480d8-de0a-4967-b94c-81ace2b9f7518708f0cc-7157-441c-b430-d69e15ec1ab9432e06ef-869b-4816-b0b1-6964d81fb3e55391df34-17a6-4ed9-87af-59d10800f0ee8708f0cc-7157-441c-b430-d69e15ec1ab9188d37480d8-de0a-4967-b94c-81ace2b9f751:8708f0cc-7157-441c-b430-d69e15ec1ab9:432e06ef-869b-4816-b0b1-6964d81fb3e50001-01-01T00:00:00HighTitleAn adversary can bypass authentication due to non-standard Azure AD authentication schemesUserThreatCategorySpoofingUserThreatShortDescriptionSpoofing is when a process or entity is something other than its claimed identity. Examples include substituting a process, a file, website or a network addressUserThreatDescriptionAn adversary can bypass authentication due to non-standard Azure AD authentication schemesInteractionStringGET OpenId-ConfigurationPossibleMitigationsUse standard authentication scenarios supported by Azure Active Directory. Refer: <a href="https://aka.ms/tmtauthn#authn-aad">https://aka.ms/tmtauthn#authn-aad</a>PriorityHighSDLPhaseImplementationd37480d8-de0a-4967-b94c-81ace2b9f751AutoGenerated432e06ef-869b-4816-b0b1-6964d81fb3e5TH11falsefalseTH12d37480d8-de0a-4967-b94c-81ace2b9f7518708f0cc-7157-441c-b430-d69e15ec1ab9432e06ef-869b-4816-b0b1-6964d81fb3e55391df34-17a6-4ed9-87af-59d10800f0ee8708f0cc-7157-441c-b430-d69e15ec1ab9189d37480d8-de0a-4967-b94c-81ace2b9f751:8708f0cc-7157-441c-b430-d69e15ec1ab9:432e06ef-869b-4816-b0b1-6964d81fb3e50001-01-01T00:00:00HighTitleAn adversary can get access to a user's session by replaying authentication tokens UserThreatCategorySpoofingUserThreatShortDescriptionSpoofing is when a process or entity is something other than its claimed identity. Examples include substituting a process, a file, website or a network addressUserThreatDescriptionAn adversary can get access to a user's session by replaying authentication tokens InteractionStringGET OpenId-ConfigurationPossibleMitigationsEnsure that TokenReplayCache is used to prevent the replay of ADAL authentication tokens. Refer: <a href="https://aka.ms/tmtauthn#tokenreplaycache-adal">https://aka.ms/tmtauthn#tokenreplaycache-adal</a>PriorityHighSDLPhaseImplementationd37480d8-de0a-4967-b94c-81ace2b9f751AutoGenerated432e06ef-869b-4816-b0b1-6964d81fb3e5TH12falsefalseTH75d37480d8-de0a-4967-b94c-81ace2b9f7518708f0cc-7157-441c-b430-d69e15ec1ab9432e06ef-869b-4816-b0b1-6964d81fb3e55391df34-17a6-4ed9-87af-59d10800f0ee8708f0cc-7157-441c-b430-d69e15ec1ab9190d37480d8-de0a-4967-b94c-81ace2b9f751:8708f0cc-7157-441c-b430-d69e15ec1ab9:432e06ef-869b-4816-b0b1-6964d81fb3e50001-01-01T00:00:00HighTitleAn adversary can get access to a user's session due to improper logout from Azure ADUserThreatCategorySpoofingUserThreatShortDescriptionSpoofing is when a process or entity is something other than its claimed identity. Examples include substituting a process, a file, website or a network addressUserThreatDescriptionThe session cookies is the identifier by which the server knows the identity of current user for each incoming request. If the attacker is able to steal the user token he would be able to access all user data and perform all actions on behalf of user. InteractionStringGET OpenId-ConfigurationPossibleMitigationsImplement proper logout using ADAL methods when using Azure AD. Refer: <a href="https://aka.ms/tmtsmgmt#logout-adal">https://aka.ms/tmtsmgmt#logout-adal</a>PriorityHighSDLPhaseImplementationd37480d8-de0a-4967-b94c-81ace2b9f751AutoGenerated432e06ef-869b-4816-b0b1-6964d81fb3e5TH75falsefalseTH2687952830-0247-4d6d-b43e-3e2f46f47ed06bdd8677-730d-4713-8037-5aebcf82a6bed37480d8-de0a-4967-b94c-81ace2b9f7515391df34-17a6-4ed9-87af-59d10800f0ee6bdd8677-730d-4713-8037-5aebcf82a6be19187952830-0247-4d6d-b43e-3e2f46f47ed0:6bdd8677-730d-4713-8037-5aebcf82a6be:d37480d8-de0a-4967-b94c-81ace2b9f7510001-01-01T00:00:00HighTitleAn adversary can perform action on behalf of other user due to lack of controls against cross domain requestsUserThreatCategoryDenial of ServiceUserThreatShortDescriptionDenial of Service happens when the process or a datastore is not able to service incoming requests or perform up to specUserThreatDescriptionFailure to restrict requests originating from third party domains may result in unauthorized actions or access of dataInteractionStringGET Raw Call RecordPossibleMitigationsEnsure that authenticated ASP.NET pages incorporate UI Redressing or clickjacking defences. Refer: <a href="https://aka.ms/tmtconfigmgmt#ui-defenses">https://aka.ms/tmtconfigmgmt#ui-defenses</a> Ensure that only trusted origins are allowed if CORS is enabled on ASP.NET Web Applications. Refer: <a href="https://aka.ms/tmtconfigmgmt#cors-aspnet">https://aka.ms/tmtconfigmgmt#cors-aspnet</a> Mitigate against Cross-Site Request Forgery (CSRF) attacks on ASP.NET web pages. Refer: <a href="https://aka.ms/tmtsmgmt#csrf-asp">https://aka.ms/tmtsmgmt#csrf-asp</a>PriorityHighSDLPhaseImplementation87952830-0247-4d6d-b43e-3e2f46f47ed0AutoGeneratedd37480d8-de0a-4967-b94c-81ace2b9f751TH26falsefalseTH2787952830-0247-4d6d-b43e-3e2f46f47ed06bdd8677-730d-4713-8037-5aebcf82a6bed37480d8-de0a-4967-b94c-81ace2b9f7515391df34-17a6-4ed9-87af-59d10800f0ee6bdd8677-730d-4713-8037-5aebcf82a6be19287952830-0247-4d6d-b43e-3e2f46f47ed0:6bdd8677-730d-4713-8037-5aebcf82a6be:d37480d8-de0a-4967-b94c-81ace2b9f7510001-01-01T00:00:00HighTitleAn adversary may bypass critical steps or perform actions on behalf of other users (victims) due to improper validation logicUserThreatCategoryElevation of PrivilegesUserThreatShortDescriptionA user subject gains increased capability or privilege by taking advantage of an implementation bugUserThreatDescriptionFailure to restrict the privileges and access rights to the application to individuals who require the privileges or access rights may result into unauthorized use of data due to inappropriate rights settings and validation.InteractionStringGET Raw Call RecordPossibleMitigationsEnsure that administrative interfaces are appropriately locked down. Refer: <a href="https://aka.ms/tmtauthn#admin-interface-lockdown">https://aka.ms/tmtauthn#admin-interface-lockdown</a> Enforce sequential step order when processing business logic flows. Refer: <a href="https://aka.ms/tmtauthz#sequential-logic">https://aka.ms/tmtauthz#sequential-logic</a> Ensure that proper authorization is in place and principle of least privileges is followed. Refer: <a href="https://aka.ms/tmtauthz#principle-least-privilege">https://aka.ms/tmtauthz#principle-least-privilege</a> Business logic and resource access authorization decisions should not be based on incoming request parameters. Refer: <a href="https://aka.ms/tmtauthz#logic-request-parameters">https://aka.ms/tmtauthz#logic-request-parameters</a> Ensure that content and resources are not enumerable or accessible via forceful browsing. Refer: <a href="https://aka.ms/tmtauthz#enumerable-browsing">https://aka.ms/tmtauthz#enumerable-browsing</a>PriorityHighSDLPhaseImplementation87952830-0247-4d6d-b43e-3e2f46f47ed0AutoGeneratedd37480d8-de0a-4967-b94c-81ace2b9f751TH27falsefalseTH10187952830-0247-4d6d-b43e-3e2f46f47ed06bdd8677-730d-4713-8037-5aebcf82a6bed37480d8-de0a-4967-b94c-81ace2b9f7515391df34-17a6-4ed9-87af-59d10800f0ee6bdd8677-730d-4713-8037-5aebcf82a6be19387952830-0247-4d6d-b43e-3e2f46f47ed0:6bdd8677-730d-4713-8037-5aebcf82a6be:d37480d8-de0a-4967-b94c-81ace2b9f7510001-01-01T00:00:00HighTitleAn adversary can reverse weakly encrypted or hashed contentUserThreatCategoryInformation DisclosureUserThreatShortDescriptionInformation disclosure happens when the information can be read by an unauthorized partyUserThreatDescriptionAn adversary can reverse weakly encrypted or hashed contentInteractionStringGET Raw Call RecordPossibleMitigationsDo not expose security details in error messages. Refer: <a href="https://aka.ms/tmtxmgmt#messages">https://aka.ms/tmtxmgmt#messages</a> Implement Default error handling page. Refer: <a href="https://aka.ms/tmtxmgmt#default">https://aka.ms/tmtxmgmt#default</a> Set Deployment Method to Retail in IIS. Refer: <a href="https://aka.ms/tmtxmgmt#deployment">https://aka.ms/tmtxmgmt#deployment</a> Use only approved symmetric block ciphers and key lengths. Refer: <a href="https://aka.ms/tmtcrypto#cipher-length">https://aka.ms/tmtcrypto#cipher-length</a> Use approved block cipher modes and initialization vectors for symmetric ciphers. Refer: <a href="https://aka.ms/tmtcrypto#vector-ciphers">https://aka.ms/tmtcrypto#vector-ciphers</a> Use approved asymmetric algorithms, key lengths, and padding. Refer: <a href="https://aka.ms/tmtcrypto#padding">https://aka.ms/tmtcrypto#padding</a> Use approved random number generators. Refer: <a href="https://aka.ms/tmtcrypto#numgen">https://aka.ms/tmtcrypto#numgen</a> Do not use symmetric stream ciphers. Refer: <a href="https://aka.ms/tmtcrypto#stream-ciphers">https://aka.ms/tmtcrypto#stream-ciphers</a> Use approved MAC/HMAC/keyed hash algorithms. Refer: <a href="https://aka.ms/tmtcrypto#mac-hash">https://aka.ms/tmtcrypto#mac-hash</a> Use only approved cryptographic hash functions. Refer: <a href="https://aka.ms/tmtcrypto#hash-functions">https://aka.ms/tmtcrypto#hash-functions</a> Verify X.509 certificates used to authenticate SSL, TLS, and DTLS connections. Refer: <a href="https://aka.ms/tmtcommsec#x509-ssltls">https://aka.ms/tmtcommsec#x509-ssltls</a>PriorityHighSDLPhaseImplementation87952830-0247-4d6d-b43e-3e2f46f47ed0AutoGeneratedd37480d8-de0a-4967-b94c-81ace2b9f751TH101falsefalseTH10287952830-0247-4d6d-b43e-3e2f46f47ed06bdd8677-730d-4713-8037-5aebcf82a6bed37480d8-de0a-4967-b94c-81ace2b9f7515391df34-17a6-4ed9-87af-59d10800f0ee6bdd8677-730d-4713-8037-5aebcf82a6be19487952830-0247-4d6d-b43e-3e2f46f47ed0:6bdd8677-730d-4713-8037-5aebcf82a6be:d37480d8-de0a-4967-b94c-81ace2b9f7510001-01-01T00:00:00HighTitleAn adversary may gain access to sensitive data from log filesUserThreatCategoryInformation DisclosureUserThreatShortDescriptionInformation disclosure happens when the information can be read by an unauthorized partyUserThreatDescriptionAn adversary may gain access to sensitive data from log filesInteractionStringGET Raw Call RecordPossibleMitigationsEnsure that the application does not log sensitive user data. Refer: <a href="https://aka.ms/tmtauditlog#log-sensitive-data">https://aka.ms/tmtauditlog#log-sensitive-data</a> Ensure that Audit and Log Files have Restricted Access. Refer: <a href="https://aka.ms/tmtauditlog#log-restricted-access">https://aka.ms/tmtauditlog#log-restricted-access</a>PriorityHighSDLPhaseImplementation87952830-0247-4d6d-b43e-3e2f46f47ed0AutoGeneratedd37480d8-de0a-4967-b94c-81ace2b9f751TH102falsefalseTH10387952830-0247-4d6d-b43e-3e2f46f47ed06bdd8677-730d-4713-8037-5aebcf82a6bed37480d8-de0a-4967-b94c-81ace2b9f7515391df34-17a6-4ed9-87af-59d10800f0ee6bdd8677-730d-4713-8037-5aebcf82a6be19587952830-0247-4d6d-b43e-3e2f46f47ed0:6bdd8677-730d-4713-8037-5aebcf82a6be:d37480d8-de0a-4967-b94c-81ace2b9f7510001-01-01T00:00:00HighTitleAn adversary may gain access to unmasked sensitive data such as credit card numbersUserThreatCategoryInformation DisclosureUserThreatShortDescriptionInformation disclosure happens when the information can be read by an unauthorized partyUserThreatDescriptionAn adversary may gain access to unmasked sensitive data such as credit card numbersInteractionStringGET Raw Call RecordPossibleMitigationsEnsure that sensitive data displayed on the user screen is masked. Refer: <a href="https://aka.ms/tmtdata#data-mask">https://aka.ms/tmtdata#data-mask</a>PriorityHighSDLPhaseImplementation87952830-0247-4d6d-b43e-3e2f46f47ed0AutoGeneratedd37480d8-de0a-4967-b94c-81ace2b9f751TH103falsefalseTH8087952830-0247-4d6d-b43e-3e2f46f47ed06bdd8677-730d-4713-8037-5aebcf82a6bed37480d8-de0a-4967-b94c-81ace2b9f7515391df34-17a6-4ed9-87af-59d10800f0ee6bdd8677-730d-4713-8037-5aebcf82a6be19687952830-0247-4d6d-b43e-3e2f46f47ed0:6bdd8677-730d-4713-8037-5aebcf82a6be:d37480d8-de0a-4967-b94c-81ace2b9f7510001-01-01T00:00:00MediumTitleAn adversary can gain access to certain pages or the site as a whole.UserThreatCategoryInformation DisclosureUserThreatShortDescriptionInformation disclosure happens when the information can be read by an unauthorized partyUserThreatDescriptionRobots.txt is often found in your site's root directory and exists to regulate the bots that crawl your site. This is where you can grant or deny permission to all or some specific search engine robots to access certain pages or your site as a whole. The standard for this file was developed in 1994 and is known as the Robots Exclusion Standard or Robots Exclusion Protocol. Detailed info about the robots.txt protocol can be found at robotstxt.org.InteractionStringGET Raw Call RecordPossibleMitigationsEnsure that administrative interfaces are appropriately locked down. Refer: <a href="https://aka.ms/tmtauthn#admin-interface-lockdown">https://aka.ms/tmtauthn#admin-interface-lockdown</a>PriorityMediumSDLPhaseImplementation87952830-0247-4d6d-b43e-3e2f46f47ed0AutoGeneratedd37480d8-de0a-4967-b94c-81ace2b9f751TH80falsefalseTH987952830-0247-4d6d-b43e-3e2f46f47ed06bdd8677-730d-4713-8037-5aebcf82a6bed37480d8-de0a-4967-b94c-81ace2b9f7515391df34-17a6-4ed9-87af-59d10800f0ee6bdd8677-730d-4713-8037-5aebcf82a6be19787952830-0247-4d6d-b43e-3e2f46f47ed0:6bdd8677-730d-4713-8037-5aebcf82a6be:d37480d8-de0a-4967-b94c-81ace2b9f7510001-01-01T00:00:00HighTitleAn adversary can gain access to sensitive data by sniffing traffic to Web ApplicationUserThreatCategoryInformation DisclosureUserThreatShortDescriptionInformation disclosure happens when the information can be read by an unauthorized partyUserThreatDescriptionAn adversary may conduct man in the middle attack and downgrade TLS connection to clear text protocol, or forcing browser communication to pass through a proxy server that he controls. This may happen because the application may use mixed content or HTTP Strict Transport Security policy is not ensured.InteractionStringGET Raw Call RecordPossibleMitigationsApplications available over HTTPS must use secure cookies. Refer: <a href="https://aka.ms/tmtsmgmt#https-secure-cookies">https://aka.ms/tmtsmgmt#https-secure-cookies</a> Enable HTTP Strict Transport Security (HSTS). Refer: <a href="https://aka.ms/tmtcommsec#http-hsts">https://aka.ms/tmtcommsec#http-hsts</a>PriorityHighSDLPhaseImplementation87952830-0247-4d6d-b43e-3e2f46f47ed0AutoGeneratedd37480d8-de0a-4967-b94c-81ace2b9f751TH9falsefalseTH9487952830-0247-4d6d-b43e-3e2f46f47ed06bdd8677-730d-4713-8037-5aebcf82a6bed37480d8-de0a-4967-b94c-81ace2b9f7515391df34-17a6-4ed9-87af-59d10800f0ee6bdd8677-730d-4713-8037-5aebcf82a6be19887952830-0247-4d6d-b43e-3e2f46f47ed0:6bdd8677-730d-4713-8037-5aebcf82a6be:d37480d8-de0a-4967-b94c-81ace2b9f7510001-01-01T00:00:00HighTitleAn adversary can gain access to sensitive information through error messagesUserThreatCategoryInformation DisclosureUserThreatShortDescriptionInformation disclosure happens when the information can be read by an unauthorized partyUserThreatDescriptionAn adversary can gain access to sensitive data such as the following, through verbose error messages - Server names - Connection strings - Usernames - Passwords - SQL procedures - Details of dynamic SQL failures - Stack trace and lines of code - Variables stored in memory - Drive and folder locations - Application install points - Host configuration settings - Other internal application details InteractionStringGET Raw Call RecordPossibleMitigationsDo not expose security details in error messages. Refer: <a href="https://aka.ms/tmtxmgmt#messages">https://aka.ms/tmtxmgmt#messages</a> Implement Default error handling page. Refer: <a href="https://aka.ms/tmtxmgmt#default">https://aka.ms/tmtxmgmt#default</a> Set Deployment Method to Retail in IIS. Refer: <a href="https://aka.ms/tmtxmgmt#deployment">https://aka.ms/tmtxmgmt#deployment</a> Exceptions should fail safely. Refer: <a href="https://aka.ms/tmtxmgmt#fail">https://aka.ms/tmtxmgmt#fail</a> ASP.NET applications must disable tracing and debugging prior to deployment. Refer: <a href="https://aka.ms/tmtconfigmgmt#trace-deploy">https://aka.ms/tmtconfigmgmt#trace-deploy</a> Implement controls to prevent username enumeration. Refer: <a href="https://aka.ms/tmtauthn#controls-username-enum">https://aka.ms/tmtauthn#controls-username-enum</a>PriorityHighSDLPhaseImplementation87952830-0247-4d6d-b43e-3e2f46f47ed0AutoGeneratedd37480d8-de0a-4967-b94c-81ace2b9f751TH94falsefalseTH9987952830-0247-4d6d-b43e-3e2f46f47ed06bdd8677-730d-4713-8037-5aebcf82a6bed37480d8-de0a-4967-b94c-81ace2b9f7515391df34-17a6-4ed9-87af-59d10800f0ee6bdd8677-730d-4713-8037-5aebcf82a6be19987952830-0247-4d6d-b43e-3e2f46f47ed0:6bdd8677-730d-4713-8037-5aebcf82a6be:d37480d8-de0a-4967-b94c-81ace2b9f7510001-01-01T00:00:00HighTitleAn adversary may gain access to sensitive data from uncleared browser cacheUserThreatCategoryInformation DisclosureUserThreatShortDescriptionInformation disclosure happens when the information can be read by an unauthorized partyUserThreatDescriptionAn adversary may gain access to sensitive data from uncleared browser cacheInteractionStringGET Raw Call RecordPossibleMitigationsEnsure that sensitive content is not cached on the browser. Refer: <a href="https://aka.ms/tmtdata#cache-browser">https://aka.ms/tmtdata#cache-browser</a>PriorityHighSDLPhaseImplementation87952830-0247-4d6d-b43e-3e2f46f47ed0AutoGeneratedd37480d8-de0a-4967-b94c-81ace2b9f751TH99falsefalseTH3087952830-0247-4d6d-b43e-3e2f46f47ed06bdd8677-730d-4713-8037-5aebcf82a6bed37480d8-de0a-4967-b94c-81ace2b9f7515391df34-17a6-4ed9-87af-59d10800f0ee6bdd8677-730d-4713-8037-5aebcf82a6be20087952830-0247-4d6d-b43e-3e2f46f47ed0:6bdd8677-730d-4713-8037-5aebcf82a6be:d37480d8-de0a-4967-b94c-81ace2b9f7510001-01-01T00:00:00MediumTitleAttacker can deny the malicious act and remove the attack foot prints leading to repudiation issuesUserThreatCategoryRepudiationUserThreatShortDescriptionRepudiation threats involve an adversary denying that something happenedUserThreatDescriptionProper logging of all security events and user actions builds traceability in a system and denies any possible repudiation issues. In the absence of proper auditing and logging controls, it would become impossible to implement any accountability in a systemInteractionStringGET Raw Call RecordPossibleMitigationsEnsure that auditing and logging is enforced on the application. Refer: <a href="https://aka.ms/tmtauditlog#auditing">https://aka.ms/tmtauditlog#auditing</a> Ensure that log rotation and separation are in place. Refer: <a href="https://aka.ms/tmtauditlog#log-rotation">https://aka.ms/tmtauditlog#log-rotation</a> Ensure that Audit and Log Files have Restricted Access. Refer: <a href="https://aka.ms/tmtauditlog#log-restricted-access">https://aka.ms/tmtauditlog#log-restricted-access</a> Ensure that User Management Events are Logged. Refer: <a href="https://aka.ms/tmtauditlog#user-management">https://aka.ms/tmtauditlog#user-management</a>PriorityMediumSDLPhaseImplementation87952830-0247-4d6d-b43e-3e2f46f47ed0AutoGeneratedd37480d8-de0a-4967-b94c-81ace2b9f751TH30falsefalseTH2287952830-0247-4d6d-b43e-3e2f46f47ed06bdd8677-730d-4713-8037-5aebcf82a6bed37480d8-de0a-4967-b94c-81ace2b9f7515391df34-17a6-4ed9-87af-59d10800f0ee6bdd8677-730d-4713-8037-5aebcf82a6be20187952830-0247-4d6d-b43e-3e2f46f47ed0:6bdd8677-730d-4713-8037-5aebcf82a6be:d37480d8-de0a-4967-b94c-81ace2b9f7510001-01-01T00:00:00HighTitleAn adversary can get access to a user's session due to improper logout and timeoutUserThreatCategorySpoofingUserThreatShortDescriptionSpoofing is when a process or entity is something other than its claimed identity. Examples include substituting a process, a file, website or a network addressUserThreatDescriptionThe session cookies is the identifier by which the server knows the identity of current user for each incoming request. If the attacker is able to steal the user token he would be able to access all user data and perform all actions on behalf of user.InteractionStringGET Raw Call RecordPossibleMitigationsSet up session for inactivity lifetime. Refer: <a href="https://aka.ms/tmtsmgmt#inactivity-lifetime">https://aka.ms/tmtsmgmt#inactivity-lifetime</a> Implement proper logout from the application. Refer: <a href="https://aka.ms/tmtsmgmt#proper-app-logout">https://aka.ms/tmtsmgmt#proper-app-logout</a>PriorityHighSDLPhaseImplementation87952830-0247-4d6d-b43e-3e2f46f47ed0AutoGeneratedd37480d8-de0a-4967-b94c-81ace2b9f751TH22falsefalseTH2387952830-0247-4d6d-b43e-3e2f46f47ed06bdd8677-730d-4713-8037-5aebcf82a6bed37480d8-de0a-4967-b94c-81ace2b9f7515391df34-17a6-4ed9-87af-59d10800f0ee6bdd8677-730d-4713-8037-5aebcf82a6be20287952830-0247-4d6d-b43e-3e2f46f47ed0:6bdd8677-730d-4713-8037-5aebcf82a6be:d37480d8-de0a-4967-b94c-81ace2b9f7510001-01-01T00:00:00HighTitleAn adversary can get access to a user's session due to insecure coding practicesUserThreatCategorySpoofingUserThreatShortDescriptionSpoofing is when a process or entity is something other than its claimed identity. Examples include substituting a process, a file, website or a network addressUserThreatDescriptionThe session cookies is the identifier by which the server knows the identity of current user for each incoming request. If the attacker is able to steal the user token he would be able to access all user data and perform all actions on behalf of user.InteractionStringGET Raw Call RecordPossibleMitigationsEnable ValidateRequest attribute on ASP.NET Pages. Refer: <a href="https://aka.ms/tmtconfigmgmt#validate-aspnet">https://aka.ms/tmtconfigmgmt#validate-aspnet</a> Encode untrusted web output prior to rendering. Refer: <a href="https://aka.ms/tmtinputval#rendering">https://aka.ms/tmtinputval#rendering</a> Avoid using Html.Raw in Razor views. Refer: <a href="https://aka.ms/tmtinputval#html-razor">https://aka.ms/tmtinputval#html-razor</a> Sanitization should be applied on form fields that accept all characters e.g, rich text editor . Refer: <a href="https://aka.ms/tmtinputval#richtext">https://aka.ms/tmtinputval#richtext</a> Do not assign DOM elements to sinks that do not have inbuilt encoding . Refer: <a href="https://aka.ms/tmtinputval#inbuilt-encode">https://aka.ms/tmtinputval#inbuilt-encode</a>PriorityHighSDLPhaseImplementation87952830-0247-4d6d-b43e-3e2f46f47ed0AutoGeneratedd37480d8-de0a-4967-b94c-81ace2b9f751TH23falsefalseTH3287952830-0247-4d6d-b43e-3e2f46f47ed06bdd8677-730d-4713-8037-5aebcf82a6bed37480d8-de0a-4967-b94c-81ace2b9f7515391df34-17a6-4ed9-87af-59d10800f0ee6bdd8677-730d-4713-8037-5aebcf82a6be20387952830-0247-4d6d-b43e-3e2f46f47ed0:6bdd8677-730d-4713-8037-5aebcf82a6be:d37480d8-de0a-4967-b94c-81ace2b9f7510001-01-01T00:00:00HighTitleAn adversary can spoof the target web application due to insecure TLS certificate configurationUserThreatCategorySpoofingUserThreatShortDescriptionSpoofing is when a process or entity is something other than its claimed identity. Examples include substituting a process, a file, website or a network addressUserThreatDescriptionEnsure that TLS certificate parameters are configured with correct valuesInteractionStringGET Raw Call RecordPossibleMitigationsVerify X.509 certificates used to authenticate SSL, TLS, and DTLS connections. Refer: <a href="https://aka.ms/tmtcommsec#x509-ssltls">https://aka.ms/tmtcommsec#x509-ssltls</a>PriorityHighSDLPhaseImplementation87952830-0247-4d6d-b43e-3e2f46f47ed0AutoGeneratedd37480d8-de0a-4967-b94c-81ace2b9f751TH32falsefalseTH787952830-0247-4d6d-b43e-3e2f46f47ed06bdd8677-730d-4713-8037-5aebcf82a6bed37480d8-de0a-4967-b94c-81ace2b9f7515391df34-17a6-4ed9-87af-59d10800f0ee6bdd8677-730d-4713-8037-5aebcf82a6be20487952830-0247-4d6d-b43e-3e2f46f47ed0:6bdd8677-730d-4713-8037-5aebcf82a6be:d37480d8-de0a-4967-b94c-81ace2b9f7510001-01-01T00:00:00HighTitleAn adversary can steal sensitive data like user credentialsUserThreatCategorySpoofingUserThreatShortDescriptionSpoofing is when a process or entity is something other than its claimed identity. Examples include substituting a process, a file, website or a network addressUserThreatDescriptionAttackers can exploit weaknesses in system to steal user credentials. Downstream and upstream components are often accessed by using credentials stored in configuration stores. Attackers may steal the upstream or downstream component credentials. Attackers may steal credentials if, Credentials are stored and sent in clear text, Weak input validation coupled with dynamic sql queries, Password retrieval mechanism are poor, InteractionStringGET Raw Call RecordPossibleMitigationsExplicitly disable the autocomplete HTML attribute in sensitive forms and inputs. Refer: <a href="https://aka.ms/tmtdata#autocomplete-input">https://aka.ms/tmtdata#autocomplete-input</a> Perform input validation and filtering on all string type Model properties. Refer: <a href="https://aka.ms/tmtinputval#typemodel">https://aka.ms/tmtinputval#typemodel</a> Validate all redirects within the application are closed or done safely. Refer: <a href="https://aka.ms/tmtinputval#redirect-safe">https://aka.ms/tmtinputval#redirect-safe</a> Enable step up or adaptive authentication. Refer: <a href="https://aka.ms/tmtauthn#step-up-adaptive-authn">https://aka.ms/tmtauthn#step-up-adaptive-authn</a> Implement forgot password functionalities securely. Refer: <a href="https://aka.ms/tmtauthn#forgot-pword-fxn">https://aka.ms/tmtauthn#forgot-pword-fxn</a> Ensure that password and account policy are implemented. Refer: <a href="https://aka.ms/tmtauthn#pword-account-policy">https://aka.ms/tmtauthn#pword-account-policy</a> Implement input validation on all string type parameters accepted by Controller methods. Refer: <a href="https://aka.ms/tmtinputval#string-method">https://aka.ms/tmtinputval#string-method</a>PriorityHighSDLPhaseImplementation87952830-0247-4d6d-b43e-3e2f46f47ed0AutoGeneratedd37480d8-de0a-4967-b94c-81ace2b9f751TH7falsefalseTH887952830-0247-4d6d-b43e-3e2f46f47ed06bdd8677-730d-4713-8037-5aebcf82a6bed37480d8-de0a-4967-b94c-81ace2b9f7515391df34-17a6-4ed9-87af-59d10800f0ee6bdd8677-730d-4713-8037-5aebcf82a6be20587952830-0247-4d6d-b43e-3e2f46f47ed0:6bdd8677-730d-4713-8037-5aebcf82a6be:d37480d8-de0a-4967-b94c-81ace2b9f7510001-01-01T00:00:00HighTitleAttackers can steal user session cookies due to insecure cookie attributesUserThreatCategorySpoofingUserThreatShortDescriptionSpoofing is when a process or entity is something other than its claimed identity. Examples include substituting a process, a file, website or a network addressUserThreatDescriptionThe session cookies is the identifier by which the server knows the identity of current user for each incoming request. If the attacker is able to steal the user token he would be able to access all user data and perform all actions on behalf of user. InteractionStringGET Raw Call RecordPossibleMitigationsApplications available over HTTPS must use secure cookies. Refer: <a href="https://aka.ms/tmtsmgmt#https-secure-cookies">https://aka.ms/tmtsmgmt#https-secure-cookies</a> All http based application should specify http only for cookie definition. Refer: <a href="https://aka.ms/tmtsmgmt#cookie-definition">https://aka.ms/tmtsmgmt#cookie-definition</a>PriorityHighSDLPhaseImplementation87952830-0247-4d6d-b43e-3e2f46f47ed0AutoGeneratedd37480d8-de0a-4967-b94c-81ace2b9f751TH8falsefalseTH8187952830-0247-4d6d-b43e-3e2f46f47ed06bdd8677-730d-4713-8037-5aebcf82a6bed37480d8-de0a-4967-b94c-81ace2b9f7515391df34-17a6-4ed9-87af-59d10800f0ee6bdd8677-730d-4713-8037-5aebcf82a6be20687952830-0247-4d6d-b43e-3e2f46f47ed0:6bdd8677-730d-4713-8037-5aebcf82a6be:d37480d8-de0a-4967-b94c-81ace2b9f7510001-01-01T00:00:00HighTitleAn adversary can create a fake website and launch phishing attacksUserThreatCategorySpoofingUserThreatShortDescriptionSpoofing is when a process or entity is something other than its claimed identity. Examples include substituting a process, a file, website or a network addressUserThreatDescriptionPhishing is attempted to obtain sensitive information such as usernames, passwords, and credit card details (and sometimes, indirectly, money), often for malicious reasons, by masquerading as a Web Server which is a trustworthy entity in electronic communicationInteractionStringGET Raw Call RecordPossibleMitigationsVerify X.509 certificates used to authenticate SSL, TLS, and DTLS connections. Refer: <a href="https://aka.ms/tmtcommsec#x509-ssltls">https://aka.ms/tmtcommsec#x509-ssltls</a> Ensure that authenticated ASP.NET pages incorporate UI Redressing or clickjacking defences. Refer: <a href="https://aka.ms/tmtconfigmgmt#ui-defenses">https://aka.ms/tmtconfigmgmt#ui-defenses</a> Validate all redirects within the application are closed or done safely. Refer: <a href="https://aka.ms/tmtinputval#redirect-safe">https://aka.ms/tmtinputval#redirect-safe</a>PriorityHighSDLPhaseImplementation87952830-0247-4d6d-b43e-3e2f46f47ed0AutoGeneratedd37480d8-de0a-4967-b94c-81ace2b9f751TH81falsefalseTH8687952830-0247-4d6d-b43e-3e2f46f47ed06bdd8677-730d-4713-8037-5aebcf82a6bed37480d8-de0a-4967-b94c-81ace2b9f7515391df34-17a6-4ed9-87af-59d10800f0ee6bdd8677-730d-4713-8037-5aebcf82a6be20787952830-0247-4d6d-b43e-3e2f46f47ed0:6bdd8677-730d-4713-8037-5aebcf82a6be:d37480d8-de0a-4967-b94c-81ace2b9f7510001-01-01T00:00:00HighTitleAn adversary may spoof Browser and gain access to Web ApplicationUserThreatCategorySpoofingUserThreatShortDescriptionSpoofing is when a process or entity is something other than its claimed identity. Examples include substituting a process, a file, website or a network addressUserThreatDescriptionIf proper authentication is not in place, an adversary can spoof a source process or external entity and gain unauthorized access to the Web ApplicationInteractionStringGET Raw Call RecordPossibleMitigationsConsider using a standard authentication mechanism to authenticate to Web Application. Refer: <a href="https://aka.ms/tmtauthn#standard-authn-web-app">https://aka.ms/tmtauthn#standard-authn-web-app</a>PriorityHighSDLPhaseDesign87952830-0247-4d6d-b43e-3e2f46f47ed0AutoGeneratedd37480d8-de0a-4967-b94c-81ace2b9f751TH86falsefalseTH2487952830-0247-4d6d-b43e-3e2f46f47ed06bdd8677-730d-4713-8037-5aebcf82a6bed37480d8-de0a-4967-b94c-81ace2b9f7515391df34-17a6-4ed9-87af-59d10800f0ee6bdd8677-730d-4713-8037-5aebcf82a6be20887952830-0247-4d6d-b43e-3e2f46f47ed0:6bdd8677-730d-4713-8037-5aebcf82a6be:d37480d8-de0a-4967-b94c-81ace2b9f7510001-01-01T00:00:00HighTitleAn adversary can deface the target web application by injecting malicious code or uploading dangerous filesUserThreatCategoryTamperingUserThreatShortDescriptionTampering is the act of altering the bits. Tampering with a process involves changing bits in the running process. Similarly, Tampering with a data flow involves changing bits on the wire or between two running processesUserThreatDescriptionWebsite defacement is an attack on a website where the attacker changes the visual appearance of the site or a webpage. InteractionStringGET Raw Call RecordPossibleMitigationsImplement Content Security Policy (CSP), and disable inline javascript. Refer: <a href="https://aka.ms/tmtconfigmgmt#csp-js">https://aka.ms/tmtconfigmgmt#csp-js</a> Enable browser's XSS filter. Refer: <a href="https://aka.ms/tmtconfigmgmt#xss-filter">https://aka.ms/tmtconfigmgmt#xss-filter</a> Access third party javascripts from trusted sources only. Refer: <a href="https://aka.ms/tmtconfigmgmt#js-trusted">https://aka.ms/tmtconfigmgmt#js-trusted</a> Enable ValidateRequest attribute on ASP.NET Pages. Refer: <a href="https://aka.ms/tmtconfigmgmt#validate-aspnet">https://aka.ms/tmtconfigmgmt#validate-aspnet</a> Ensure that each page that could contain user controllable content opts out of automatic MIME sniffing . Refer: <a href="https://aka.ms/tmtinputval#out-sniffing">https://aka.ms/tmtinputval#out-sniffing</a> Use locally-hosted latest versions of JavaScript libraries . Refer: <a href="https://aka.ms/tmtconfigmgmt#local-js">https://aka.ms/tmtconfigmgmt#local-js</a> Ensure appropriate controls are in place when accepting files from users. Refer: <a href="https://aka.ms/tmtinputval#controls-users">https://aka.ms/tmtinputval#controls-users</a> Disable automatic MIME sniffing. Refer: <a href="https://aka.ms/tmtconfigmgmt#mime-sniff">https://aka.ms/tmtconfigmgmt#mime-sniff</a> Encode untrusted web output prior to rendering. Refer: <a href="https://aka.ms/tmtinputval#rendering">https://aka.ms/tmtinputval#rendering</a> Perform input validation and filtering on all string type Model properties. Refer: <a href="https://aka.ms/tmtinputval#typemodel">https://aka.ms/tmtinputval#typemodel</a> Ensure that the system has inbuilt defences against misuse. Refer: <a href="https://aka.ms/tmtauditlog#inbuilt-defenses">https://aka.ms/tmtauditlog#inbuilt-defenses</a> Enable HTTP Strict Transport Security (HSTS). Refer: <a href="https://aka.ms/tmtcommsec#http-hsts">https://aka.ms/tmtcommsec#http-hsts</a> Implement input validation on all string type parameters accepted by Controller methods. Refer: <a href="https://aka.ms/tmtinputval#string-method">https://aka.ms/tmtinputval#string-method</a> Avoid using Html.Raw in Razor views. Refer: <a href="https://aka.ms/tmtinputval#html-razor">https://aka.ms/tmtinputval#html-razor</a> Sanitization should be applied on form fields that accept all characters e.g, rich text editor . Refer: <a href="https://aka.ms/tmtinputval#richtext">https://aka.ms/tmtinputval#richtext</a> Do not assign DOM elements to sinks that do not have inbuilt encoding . Refer: <a href="https://aka.ms/tmtinputval#inbuilt-encode">https://aka.ms/tmtinputval#inbuilt-encode</a>PriorityHighSDLPhaseImplementation87952830-0247-4d6d-b43e-3e2f46f47ed0AutoGeneratedd37480d8-de0a-4967-b94c-81ace2b9f751TH24falsefalseTH3387952830-0247-4d6d-b43e-3e2f46f47ed06bdd8677-730d-4713-8037-5aebcf82a6bed37480d8-de0a-4967-b94c-81ace2b9f7515391df34-17a6-4ed9-87af-59d10800f0ee6bdd8677-730d-4713-8037-5aebcf82a6be20987952830-0247-4d6d-b43e-3e2f46f47ed0:6bdd8677-730d-4713-8037-5aebcf82a6be:d37480d8-de0a-4967-b94c-81ace2b9f7510001-01-01T00:00:00HighTitleAn attacker steals messages off the network and replays them in order to steal a user's sessionUserThreatCategoryTamperingUserThreatShortDescriptionTampering is the act of altering the bits. Tampering with a process involves changing bits in the running process. Similarly, Tampering with a data flow involves changing bits on the wire or between two running processesUserThreatDescriptionAn attacker steals messages off the network and replays them in order to steal a user's sessionInteractionStringGET Raw Call RecordPriorityHighSDLPhaseImplementation87952830-0247-4d6d-b43e-3e2f46f47ed0AutoGeneratedd37480d8-de0a-4967-b94c-81ace2b9f751TH33falsefalseTH9687952830-0247-4d6d-b43e-3e2f46f47ed06bdd8677-730d-4713-8037-5aebcf82a6bed37480d8-de0a-4967-b94c-81ace2b9f7515391df34-17a6-4ed9-87af-59d10800f0ee6bdd8677-730d-4713-8037-5aebcf82a6be21087952830-0247-4d6d-b43e-3e2f46f47ed0:6bdd8677-730d-4713-8037-5aebcf82a6be:d37480d8-de0a-4967-b94c-81ace2b9f7510001-01-01T00:00:00HighTitleAn adversary can gain access to sensitive data by performing SQL injection through Web AppUserThreatCategoryTamperingUserThreatShortDescriptionTampering is the act of altering the bits. Tampering with a process involves changing bits in the running process. Similarly, Tampering with a data flow involves changing bits on the wire or between two running processesUserThreatDescriptionSQL injection is an attack in which malicious code is inserted into strings that are later passed to an instance of SQL Server for parsing and execution. The primary form of SQL injection consists of direct insertion of code into user-input variables that are concatenated with SQL commands and executed. A less direct attack injects malicious code into strings that are destined for storage in a table or as metadata. When the stored strings are subsequently concatenated into a dynamic SQL command, the malicious code is executed. InteractionStringGET Raw Call RecordPossibleMitigationsEnsure that type-safe parameters are used in Web Application for data access. Refer: <a href="https://aka.ms/tmtinputval#typesafe">https://aka.ms/tmtinputval#typesafe</a>PriorityHighSDLPhaseImplementation87952830-0247-4d6d-b43e-3e2f46f47ed0AutoGeneratedd37480d8-de0a-4967-b94c-81ace2b9f751TH96falsefalseTH9887952830-0247-4d6d-b43e-3e2f46f47ed06bdd8677-730d-4713-8037-5aebcf82a6bed37480d8-de0a-4967-b94c-81ace2b9f7515391df34-17a6-4ed9-87af-59d10800f0ee6bdd8677-730d-4713-8037-5aebcf82a6be21187952830-0247-4d6d-b43e-3e2f46f47ed0:6bdd8677-730d-4713-8037-5aebcf82a6be:d37480d8-de0a-4967-b94c-81ace2b9f7510001-01-01T00:00:00HighTitleAn adversary can gain access to sensitive data stored in Web App's config filesUserThreatCategoryTamperingUserThreatShortDescriptionTampering is the act of altering the bits. Tampering with a process involves changing bits in the running process. Similarly, Tampering with a data flow involves changing bits on the wire or between two running processesUserThreatDescriptionAn adversary can gain access to the config files. and if sensitive data is stored in it, it would be compromised.InteractionStringGET Raw Call RecordPossibleMitigationsEncrypt sections of Web App's configuration files that contain sensitive data. Refer: <a href="https://aka.ms/tmtdata#encrypt-data">https://aka.ms/tmtdata#encrypt-data</a>PriorityHighSDLPhaseImplementation87952830-0247-4d6d-b43e-3e2f46f47ed0AutoGeneratedd37480d8-de0a-4967-b94c-81ace2b9f751TH98falsefalseTH2687952830-0247-4d6d-b43e-3e2f46f47ed06caed8a3-cf48-48ce-a144-01dd2ed39e44d37480d8-de0a-4967-b94c-81ace2b9f7515391df34-17a6-4ed9-87af-59d10800f0ee6caed8a3-cf48-48ce-a144-01dd2ed39e4421287952830-0247-4d6d-b43e-3e2f46f47ed0:6caed8a3-cf48-48ce-a144-01dd2ed39e44:d37480d8-de0a-4967-b94c-81ace2b9f7510001-01-01T00:00:00HighTitleAn adversary can perform action on behalf of other user due to lack of controls against cross domain requestsUserThreatCategoryDenial of ServiceUserThreatShortDescriptionDenial of Service happens when the process or a datastore is not able to service incoming requests or perform up to specUserThreatDescriptionFailure to restrict requests originating from third party domains may result in unauthorized actions or access of dataInteractionStringPOST Add or Renew SubscriptionPossibleMitigationsEnsure that authenticated ASP.NET pages incorporate UI Redressing or clickjacking defences. Refer: <a href="https://aka.ms/tmtconfigmgmt#ui-defenses">https://aka.ms/tmtconfigmgmt#ui-defenses</a> Ensure that only trusted origins are allowed if CORS is enabled on ASP.NET Web Applications. Refer: <a href="https://aka.ms/tmtconfigmgmt#cors-aspnet">https://aka.ms/tmtconfigmgmt#cors-aspnet</a> Mitigate against Cross-Site Request Forgery (CSRF) attacks on ASP.NET web pages. Refer: <a href="https://aka.ms/tmtsmgmt#csrf-asp">https://aka.ms/tmtsmgmt#csrf-asp</a>PriorityHighSDLPhaseImplementation87952830-0247-4d6d-b43e-3e2f46f47ed0AutoGeneratedd37480d8-de0a-4967-b94c-81ace2b9f751TH26falsefalseTH2787952830-0247-4d6d-b43e-3e2f46f47ed06caed8a3-cf48-48ce-a144-01dd2ed39e44d37480d8-de0a-4967-b94c-81ace2b9f7515391df34-17a6-4ed9-87af-59d10800f0ee6caed8a3-cf48-48ce-a144-01dd2ed39e4421387952830-0247-4d6d-b43e-3e2f46f47ed0:6caed8a3-cf48-48ce-a144-01dd2ed39e44:d37480d8-de0a-4967-b94c-81ace2b9f7510001-01-01T00:00:00HighTitleAn adversary may bypass critical steps or perform actions on behalf of other users (victims) due to improper validation logicUserThreatCategoryElevation of PrivilegesUserThreatShortDescriptionA user subject gains increased capability or privilege by taking advantage of an implementation bugUserThreatDescriptionFailure to restrict the privileges and access rights to the application to individuals who require the privileges or access rights may result into unauthorized use of data due to inappropriate rights settings and validation.InteractionStringPOST Add or Renew SubscriptionPossibleMitigationsEnsure that administrative interfaces are appropriately locked down. Refer: <a href="https://aka.ms/tmtauthn#admin-interface-lockdown">https://aka.ms/tmtauthn#admin-interface-lockdown</a> Enforce sequential step order when processing business logic flows. Refer: <a href="https://aka.ms/tmtauthz#sequential-logic">https://aka.ms/tmtauthz#sequential-logic</a> Ensure that proper authorization is in place and principle of least privileges is followed. Refer: <a href="https://aka.ms/tmtauthz#principle-least-privilege">https://aka.ms/tmtauthz#principle-least-privilege</a> Business logic and resource access authorization decisions should not be based on incoming request parameters. Refer: <a href="https://aka.ms/tmtauthz#logic-request-parameters">https://aka.ms/tmtauthz#logic-request-parameters</a> Ensure that content and resources are not enumerable or accessible via forceful browsing. Refer: <a href="https://aka.ms/tmtauthz#enumerable-browsing">https://aka.ms/tmtauthz#enumerable-browsing</a>PriorityHighSDLPhaseImplementation87952830-0247-4d6d-b43e-3e2f46f47ed0AutoGeneratedd37480d8-de0a-4967-b94c-81ace2b9f751TH27falsefalseTH10187952830-0247-4d6d-b43e-3e2f46f47ed06caed8a3-cf48-48ce-a144-01dd2ed39e44d37480d8-de0a-4967-b94c-81ace2b9f7515391df34-17a6-4ed9-87af-59d10800f0ee6caed8a3-cf48-48ce-a144-01dd2ed39e4421487952830-0247-4d6d-b43e-3e2f46f47ed0:6caed8a3-cf48-48ce-a144-01dd2ed39e44:d37480d8-de0a-4967-b94c-81ace2b9f7510001-01-01T00:00:00HighTitleAn adversary can reverse weakly encrypted or hashed contentUserThreatCategoryInformation DisclosureUserThreatShortDescriptionInformation disclosure happens when the information can be read by an unauthorized partyUserThreatDescriptionAn adversary can reverse weakly encrypted or hashed contentInteractionStringPOST Add or Renew SubscriptionPossibleMitigationsDo not expose security details in error messages. Refer: <a href="https://aka.ms/tmtxmgmt#messages">https://aka.ms/tmtxmgmt#messages</a> Implement Default error handling page. Refer: <a href="https://aka.ms/tmtxmgmt#default">https://aka.ms/tmtxmgmt#default</a> Set Deployment Method to Retail in IIS. Refer: <a href="https://aka.ms/tmtxmgmt#deployment">https://aka.ms/tmtxmgmt#deployment</a> Use only approved symmetric block ciphers and key lengths. Refer: <a href="https://aka.ms/tmtcrypto#cipher-length">https://aka.ms/tmtcrypto#cipher-length</a> Use approved block cipher modes and initialization vectors for symmetric ciphers. Refer: <a href="https://aka.ms/tmtcrypto#vector-ciphers">https://aka.ms/tmtcrypto#vector-ciphers</a> Use approved asymmetric algorithms, key lengths, and padding. Refer: <a href="https://aka.ms/tmtcrypto#padding">https://aka.ms/tmtcrypto#padding</a> Use approved random number generators. Refer: <a href="https://aka.ms/tmtcrypto#numgen">https://aka.ms/tmtcrypto#numgen</a> Do not use symmetric stream ciphers. Refer: <a href="https://aka.ms/tmtcrypto#stream-ciphers">https://aka.ms/tmtcrypto#stream-ciphers</a> Use approved MAC/HMAC/keyed hash algorithms. Refer: <a href="https://aka.ms/tmtcrypto#mac-hash">https://aka.ms/tmtcrypto#mac-hash</a> Use only approved cryptographic hash functions. Refer: <a href="https://aka.ms/tmtcrypto#hash-functions">https://aka.ms/tmtcrypto#hash-functions</a> Verify X.509 certificates used to authenticate SSL, TLS, and DTLS connections. Refer: <a href="https://aka.ms/tmtcommsec#x509-ssltls">https://aka.ms/tmtcommsec#x509-ssltls</a>PriorityHighSDLPhaseImplementation87952830-0247-4d6d-b43e-3e2f46f47ed0AutoGeneratedd37480d8-de0a-4967-b94c-81ace2b9f751TH101falsefalseTH10287952830-0247-4d6d-b43e-3e2f46f47ed06caed8a3-cf48-48ce-a144-01dd2ed39e44d37480d8-de0a-4967-b94c-81ace2b9f7515391df34-17a6-4ed9-87af-59d10800f0ee6caed8a3-cf48-48ce-a144-01dd2ed39e4421587952830-0247-4d6d-b43e-3e2f46f47ed0:6caed8a3-cf48-48ce-a144-01dd2ed39e44:d37480d8-de0a-4967-b94c-81ace2b9f7510001-01-01T00:00:00HighTitleAn adversary may gain access to sensitive data from log filesUserThreatCategoryInformation DisclosureUserThreatShortDescriptionInformation disclosure happens when the information can be read by an unauthorized partyUserThreatDescriptionAn adversary may gain access to sensitive data from log filesInteractionStringPOST Add or Renew SubscriptionPossibleMitigationsEnsure that the application does not log sensitive user data. Refer: <a href="https://aka.ms/tmtauditlog#log-sensitive-data">https://aka.ms/tmtauditlog#log-sensitive-data</a> Ensure that Audit and Log Files have Restricted Access. Refer: <a href="https://aka.ms/tmtauditlog#log-restricted-access">https://aka.ms/tmtauditlog#log-restricted-access</a>PriorityHighSDLPhaseImplementation87952830-0247-4d6d-b43e-3e2f46f47ed0AutoGeneratedd37480d8-de0a-4967-b94c-81ace2b9f751TH102falsefalseTH10387952830-0247-4d6d-b43e-3e2f46f47ed06caed8a3-cf48-48ce-a144-01dd2ed39e44d37480d8-de0a-4967-b94c-81ace2b9f7515391df34-17a6-4ed9-87af-59d10800f0ee6caed8a3-cf48-48ce-a144-01dd2ed39e4421687952830-0247-4d6d-b43e-3e2f46f47ed0:6caed8a3-cf48-48ce-a144-01dd2ed39e44:d37480d8-de0a-4967-b94c-81ace2b9f7510001-01-01T00:00:00HighTitleAn adversary may gain access to unmasked sensitive data such as credit card numbersUserThreatCategoryInformation DisclosureUserThreatShortDescriptionInformation disclosure happens when the information can be read by an unauthorized partyUserThreatDescriptionAn adversary may gain access to unmasked sensitive data such as credit card numbersInteractionStringPOST Add or Renew SubscriptionPossibleMitigationsEnsure that sensitive data displayed on the user screen is masked. Refer: <a href="https://aka.ms/tmtdata#data-mask">https://aka.ms/tmtdata#data-mask</a>PriorityHighSDLPhaseImplementation87952830-0247-4d6d-b43e-3e2f46f47ed0AutoGeneratedd37480d8-de0a-4967-b94c-81ace2b9f751TH103falsefalseTH8087952830-0247-4d6d-b43e-3e2f46f47ed06caed8a3-cf48-48ce-a144-01dd2ed39e44d37480d8-de0a-4967-b94c-81ace2b9f7515391df34-17a6-4ed9-87af-59d10800f0ee6caed8a3-cf48-48ce-a144-01dd2ed39e4421787952830-0247-4d6d-b43e-3e2f46f47ed0:6caed8a3-cf48-48ce-a144-01dd2ed39e44:d37480d8-de0a-4967-b94c-81ace2b9f7510001-01-01T00:00:00MediumTitleAn adversary can gain access to certain pages or the site as a whole.UserThreatCategoryInformation DisclosureUserThreatShortDescriptionInformation disclosure happens when the information can be read by an unauthorized partyUserThreatDescriptionRobots.txt is often found in your site's root directory and exists to regulate the bots that crawl your site. This is where you can grant or deny permission to all or some specific search engine robots to access certain pages or your site as a whole. The standard for this file was developed in 1994 and is known as the Robots Exclusion Standard or Robots Exclusion Protocol. Detailed info about the robots.txt protocol can be found at robotstxt.org.InteractionStringPOST Add or Renew SubscriptionPossibleMitigationsEnsure that administrative interfaces are appropriately locked down. Refer: <a href="https://aka.ms/tmtauthn#admin-interface-lockdown">https://aka.ms/tmtauthn#admin-interface-lockdown</a>PriorityMediumSDLPhaseImplementation87952830-0247-4d6d-b43e-3e2f46f47ed0AutoGeneratedd37480d8-de0a-4967-b94c-81ace2b9f751TH80falsefalseTH987952830-0247-4d6d-b43e-3e2f46f47ed06caed8a3-cf48-48ce-a144-01dd2ed39e44d37480d8-de0a-4967-b94c-81ace2b9f7515391df34-17a6-4ed9-87af-59d10800f0ee6caed8a3-cf48-48ce-a144-01dd2ed39e4421887952830-0247-4d6d-b43e-3e2f46f47ed0:6caed8a3-cf48-48ce-a144-01dd2ed39e44:d37480d8-de0a-4967-b94c-81ace2b9f7510001-01-01T00:00:00HighTitleAn adversary can gain access to sensitive data by sniffing traffic to Web ApplicationUserThreatCategoryInformation DisclosureUserThreatShortDescriptionInformation disclosure happens when the information can be read by an unauthorized partyUserThreatDescriptionAn adversary may conduct man in the middle attack and downgrade TLS connection to clear text protocol, or forcing browser communication to pass through a proxy server that he controls. This may happen because the application may use mixed content or HTTP Strict Transport Security policy is not ensured.InteractionStringPOST Add or Renew SubscriptionPossibleMitigationsApplications available over HTTPS must use secure cookies. Refer: <a href="https://aka.ms/tmtsmgmt#https-secure-cookies">https://aka.ms/tmtsmgmt#https-secure-cookies</a> Enable HTTP Strict Transport Security (HSTS). Refer: <a href="https://aka.ms/tmtcommsec#http-hsts">https://aka.ms/tmtcommsec#http-hsts</a>PriorityHighSDLPhaseImplementation87952830-0247-4d6d-b43e-3e2f46f47ed0AutoGeneratedd37480d8-de0a-4967-b94c-81ace2b9f751TH9falsefalseTH9487952830-0247-4d6d-b43e-3e2f46f47ed06caed8a3-cf48-48ce-a144-01dd2ed39e44d37480d8-de0a-4967-b94c-81ace2b9f7515391df34-17a6-4ed9-87af-59d10800f0ee6caed8a3-cf48-48ce-a144-01dd2ed39e4421987952830-0247-4d6d-b43e-3e2f46f47ed0:6caed8a3-cf48-48ce-a144-01dd2ed39e44:d37480d8-de0a-4967-b94c-81ace2b9f7510001-01-01T00:00:00HighTitleAn adversary can gain access to sensitive information through error messagesUserThreatCategoryInformation DisclosureUserThreatShortDescriptionInformation disclosure happens when the information can be read by an unauthorized partyUserThreatDescriptionAn adversary can gain access to sensitive data such as the following, through verbose error messages - Server names - Connection strings - Usernames - Passwords - SQL procedures - Details of dynamic SQL failures - Stack trace and lines of code - Variables stored in memory - Drive and folder locations - Application install points - Host configuration settings - Other internal application details InteractionStringPOST Add or Renew SubscriptionPossibleMitigationsDo not expose security details in error messages. Refer: <a href="https://aka.ms/tmtxmgmt#messages">https://aka.ms/tmtxmgmt#messages</a> Implement Default error handling page. Refer: <a href="https://aka.ms/tmtxmgmt#default">https://aka.ms/tmtxmgmt#default</a> Set Deployment Method to Retail in IIS. Refer: <a href="https://aka.ms/tmtxmgmt#deployment">https://aka.ms/tmtxmgmt#deployment</a> Exceptions should fail safely. Refer: <a href="https://aka.ms/tmtxmgmt#fail">https://aka.ms/tmtxmgmt#fail</a> ASP.NET applications must disable tracing and debugging prior to deployment. Refer: <a href="https://aka.ms/tmtconfigmgmt#trace-deploy">https://aka.ms/tmtconfigmgmt#trace-deploy</a> Implement controls to prevent username enumeration. Refer: <a href="https://aka.ms/tmtauthn#controls-username-enum">https://aka.ms/tmtauthn#controls-username-enum</a>PriorityHighSDLPhaseImplementation87952830-0247-4d6d-b43e-3e2f46f47ed0AutoGeneratedd37480d8-de0a-4967-b94c-81ace2b9f751TH94falsefalseTH9987952830-0247-4d6d-b43e-3e2f46f47ed06caed8a3-cf48-48ce-a144-01dd2ed39e44d37480d8-de0a-4967-b94c-81ace2b9f7515391df34-17a6-4ed9-87af-59d10800f0ee6caed8a3-cf48-48ce-a144-01dd2ed39e4422087952830-0247-4d6d-b43e-3e2f46f47ed0:6caed8a3-cf48-48ce-a144-01dd2ed39e44:d37480d8-de0a-4967-b94c-81ace2b9f7510001-01-01T00:00:00HighTitleAn adversary may gain access to sensitive data from uncleared browser cacheUserThreatCategoryInformation DisclosureUserThreatShortDescriptionInformation disclosure happens when the information can be read by an unauthorized partyUserThreatDescriptionAn adversary may gain access to sensitive data from uncleared browser cacheInteractionStringPOST Add or Renew SubscriptionPossibleMitigationsEnsure that sensitive content is not cached on the browser. Refer: <a href="https://aka.ms/tmtdata#cache-browser">https://aka.ms/tmtdata#cache-browser</a>PriorityHighSDLPhaseImplementation87952830-0247-4d6d-b43e-3e2f46f47ed0AutoGeneratedd37480d8-de0a-4967-b94c-81ace2b9f751TH99falsefalseTH3087952830-0247-4d6d-b43e-3e2f46f47ed06caed8a3-cf48-48ce-a144-01dd2ed39e44d37480d8-de0a-4967-b94c-81ace2b9f7515391df34-17a6-4ed9-87af-59d10800f0ee6caed8a3-cf48-48ce-a144-01dd2ed39e4422187952830-0247-4d6d-b43e-3e2f46f47ed0:6caed8a3-cf48-48ce-a144-01dd2ed39e44:d37480d8-de0a-4967-b94c-81ace2b9f7510001-01-01T00:00:00MediumTitleAttacker can deny the malicious act and remove the attack foot prints leading to repudiation issuesUserThreatCategoryRepudiationUserThreatShortDescriptionRepudiation threats involve an adversary denying that something happenedUserThreatDescriptionProper logging of all security events and user actions builds traceability in a system and denies any possible repudiation issues. In the absence of proper auditing and logging controls, it would become impossible to implement any accountability in a systemInteractionStringPOST Add or Renew SubscriptionPossibleMitigationsEnsure that auditing and logging is enforced on the application. Refer: <a href="https://aka.ms/tmtauditlog#auditing">https://aka.ms/tmtauditlog#auditing</a> Ensure that log rotation and separation are in place. Refer: <a href="https://aka.ms/tmtauditlog#log-rotation">https://aka.ms/tmtauditlog#log-rotation</a> Ensure that Audit and Log Files have Restricted Access. Refer: <a href="https://aka.ms/tmtauditlog#log-restricted-access">https://aka.ms/tmtauditlog#log-restricted-access</a> Ensure that User Management Events are Logged. Refer: <a href="https://aka.ms/tmtauditlog#user-management">https://aka.ms/tmtauditlog#user-management</a>PriorityMediumSDLPhaseImplementation87952830-0247-4d6d-b43e-3e2f46f47ed0AutoGeneratedd37480d8-de0a-4967-b94c-81ace2b9f751TH30falsefalseTH2287952830-0247-4d6d-b43e-3e2f46f47ed06caed8a3-cf48-48ce-a144-01dd2ed39e44d37480d8-de0a-4967-b94c-81ace2b9f7515391df34-17a6-4ed9-87af-59d10800f0ee6caed8a3-cf48-48ce-a144-01dd2ed39e4422287952830-0247-4d6d-b43e-3e2f46f47ed0:6caed8a3-cf48-48ce-a144-01dd2ed39e44:d37480d8-de0a-4967-b94c-81ace2b9f7510001-01-01T00:00:00HighTitleAn adversary can get access to a user's session due to improper logout and timeoutUserThreatCategorySpoofingUserThreatShortDescriptionSpoofing is when a process or entity is something other than its claimed identity. Examples include substituting a process, a file, website or a network addressUserThreatDescriptionThe session cookies is the identifier by which the server knows the identity of current user for each incoming request. If the attacker is able to steal the user token he would be able to access all user data and perform all actions on behalf of user.InteractionStringPOST Add or Renew SubscriptionPossibleMitigationsSet up session for inactivity lifetime. Refer: <a href="https://aka.ms/tmtsmgmt#inactivity-lifetime">https://aka.ms/tmtsmgmt#inactivity-lifetime</a> Implement proper logout from the application. Refer: <a href="https://aka.ms/tmtsmgmt#proper-app-logout">https://aka.ms/tmtsmgmt#proper-app-logout</a>PriorityHighSDLPhaseImplementation87952830-0247-4d6d-b43e-3e2f46f47ed0AutoGeneratedd37480d8-de0a-4967-b94c-81ace2b9f751TH22falsefalseTH2387952830-0247-4d6d-b43e-3e2f46f47ed06caed8a3-cf48-48ce-a144-01dd2ed39e44d37480d8-de0a-4967-b94c-81ace2b9f7515391df34-17a6-4ed9-87af-59d10800f0ee6caed8a3-cf48-48ce-a144-01dd2ed39e4422387952830-0247-4d6d-b43e-3e2f46f47ed0:6caed8a3-cf48-48ce-a144-01dd2ed39e44:d37480d8-de0a-4967-b94c-81ace2b9f7510001-01-01T00:00:00HighTitleAn adversary can get access to a user's session due to insecure coding practicesUserThreatCategorySpoofingUserThreatShortDescriptionSpoofing is when a process or entity is something other than its claimed identity. Examples include substituting a process, a file, website or a network addressUserThreatDescriptionThe session cookies is the identifier by which the server knows the identity of current user for each incoming request. If the attacker is able to steal the user token he would be able to access all user data and perform all actions on behalf of user.InteractionStringPOST Add or Renew SubscriptionPossibleMitigationsEnable ValidateRequest attribute on ASP.NET Pages. Refer: <a href="https://aka.ms/tmtconfigmgmt#validate-aspnet">https://aka.ms/tmtconfigmgmt#validate-aspnet</a> Encode untrusted web output prior to rendering. Refer: <a href="https://aka.ms/tmtinputval#rendering">https://aka.ms/tmtinputval#rendering</a> Avoid using Html.Raw in Razor views. Refer: <a href="https://aka.ms/tmtinputval#html-razor">https://aka.ms/tmtinputval#html-razor</a> Sanitization should be applied on form fields that accept all characters e.g, rich text editor . Refer: <a href="https://aka.ms/tmtinputval#richtext">https://aka.ms/tmtinputval#richtext</a> Do not assign DOM elements to sinks that do not have inbuilt encoding . Refer: <a href="https://aka.ms/tmtinputval#inbuilt-encode">https://aka.ms/tmtinputval#inbuilt-encode</a>PriorityHighSDLPhaseImplementation87952830-0247-4d6d-b43e-3e2f46f47ed0AutoGeneratedd37480d8-de0a-4967-b94c-81ace2b9f751TH23falsefalseTH3287952830-0247-4d6d-b43e-3e2f46f47ed06caed8a3-cf48-48ce-a144-01dd2ed39e44d37480d8-de0a-4967-b94c-81ace2b9f7515391df34-17a6-4ed9-87af-59d10800f0ee6caed8a3-cf48-48ce-a144-01dd2ed39e4422487952830-0247-4d6d-b43e-3e2f46f47ed0:6caed8a3-cf48-48ce-a144-01dd2ed39e44:d37480d8-de0a-4967-b94c-81ace2b9f7510001-01-01T00:00:00HighTitleAn adversary can spoof the target web application due to insecure TLS certificate configurationUserThreatCategorySpoofingUserThreatShortDescriptionSpoofing is when a process or entity is something other than its claimed identity. Examples include substituting a process, a file, website or a network addressUserThreatDescriptionEnsure that TLS certificate parameters are configured with correct valuesInteractionStringPOST Add or Renew SubscriptionPossibleMitigationsVerify X.509 certificates used to authenticate SSL, TLS, and DTLS connections. Refer: <a href="https://aka.ms/tmtcommsec#x509-ssltls">https://aka.ms/tmtcommsec#x509-ssltls</a>PriorityHighSDLPhaseImplementation87952830-0247-4d6d-b43e-3e2f46f47ed0AutoGeneratedd37480d8-de0a-4967-b94c-81ace2b9f751TH32falsefalseTH787952830-0247-4d6d-b43e-3e2f46f47ed06caed8a3-cf48-48ce-a144-01dd2ed39e44d37480d8-de0a-4967-b94c-81ace2b9f7515391df34-17a6-4ed9-87af-59d10800f0ee6caed8a3-cf48-48ce-a144-01dd2ed39e4422587952830-0247-4d6d-b43e-3e2f46f47ed0:6caed8a3-cf48-48ce-a144-01dd2ed39e44:d37480d8-de0a-4967-b94c-81ace2b9f7510001-01-01T00:00:00HighTitleAn adversary can steal sensitive data like user credentialsUserThreatCategorySpoofingUserThreatShortDescriptionSpoofing is when a process or entity is something other than its claimed identity. Examples include substituting a process, a file, website or a network addressUserThreatDescriptionAttackers can exploit weaknesses in system to steal user credentials. Downstream and upstream components are often accessed by using credentials stored in configuration stores. Attackers may steal the upstream or downstream component credentials. Attackers may steal credentials if, Credentials are stored and sent in clear text, Weak input validation coupled with dynamic sql queries, Password retrieval mechanism are poor, InteractionStringPOST Add or Renew SubscriptionPossibleMitigationsExplicitly disable the autocomplete HTML attribute in sensitive forms and inputs. Refer: <a href="https://aka.ms/tmtdata#autocomplete-input">https://aka.ms/tmtdata#autocomplete-input</a> Perform input validation and filtering on all string type Model properties. Refer: <a href="https://aka.ms/tmtinputval#typemodel">https://aka.ms/tmtinputval#typemodel</a> Validate all redirects within the application are closed or done safely. Refer: <a href="https://aka.ms/tmtinputval#redirect-safe">https://aka.ms/tmtinputval#redirect-safe</a> Enable step up or adaptive authentication. Refer: <a href="https://aka.ms/tmtauthn#step-up-adaptive-authn">https://aka.ms/tmtauthn#step-up-adaptive-authn</a> Implement forgot password functionalities securely. Refer: <a href="https://aka.ms/tmtauthn#forgot-pword-fxn">https://aka.ms/tmtauthn#forgot-pword-fxn</a> Ensure that password and account policy are implemented. Refer: <a href="https://aka.ms/tmtauthn#pword-account-policy">https://aka.ms/tmtauthn#pword-account-policy</a> Implement input validation on all string type parameters accepted by Controller methods. Refer: <a href="https://aka.ms/tmtinputval#string-method">https://aka.ms/tmtinputval#string-method</a>PriorityHighSDLPhaseImplementation87952830-0247-4d6d-b43e-3e2f46f47ed0AutoGeneratedd37480d8-de0a-4967-b94c-81ace2b9f751TH7falsefalseTH887952830-0247-4d6d-b43e-3e2f46f47ed06caed8a3-cf48-48ce-a144-01dd2ed39e44d37480d8-de0a-4967-b94c-81ace2b9f7515391df34-17a6-4ed9-87af-59d10800f0ee6caed8a3-cf48-48ce-a144-01dd2ed39e4422687952830-0247-4d6d-b43e-3e2f46f47ed0:6caed8a3-cf48-48ce-a144-01dd2ed39e44:d37480d8-de0a-4967-b94c-81ace2b9f7510001-01-01T00:00:00HighTitleAttackers can steal user session cookies due to insecure cookie attributesUserThreatCategorySpoofingUserThreatShortDescriptionSpoofing is when a process or entity is something other than its claimed identity. Examples include substituting a process, a file, website or a network addressUserThreatDescriptionThe session cookies is the identifier by which the server knows the identity of current user for each incoming request. If the attacker is able to steal the user token he would be able to access all user data and perform all actions on behalf of user. InteractionStringPOST Add or Renew SubscriptionPossibleMitigationsApplications available over HTTPS must use secure cookies. Refer: <a href="https://aka.ms/tmtsmgmt#https-secure-cookies">https://aka.ms/tmtsmgmt#https-secure-cookies</a> All http based application should specify http only for cookie definition. Refer: <a href="https://aka.ms/tmtsmgmt#cookie-definition">https://aka.ms/tmtsmgmt#cookie-definition</a>PriorityHighSDLPhaseImplementation87952830-0247-4d6d-b43e-3e2f46f47ed0AutoGeneratedd37480d8-de0a-4967-b94c-81ace2b9f751TH8falsefalseTH8187952830-0247-4d6d-b43e-3e2f46f47ed06caed8a3-cf48-48ce-a144-01dd2ed39e44d37480d8-de0a-4967-b94c-81ace2b9f7515391df34-17a6-4ed9-87af-59d10800f0ee6caed8a3-cf48-48ce-a144-01dd2ed39e4422787952830-0247-4d6d-b43e-3e2f46f47ed0:6caed8a3-cf48-48ce-a144-01dd2ed39e44:d37480d8-de0a-4967-b94c-81ace2b9f7510001-01-01T00:00:00HighTitleAn adversary can create a fake website and launch phishing attacksUserThreatCategorySpoofingUserThreatShortDescriptionSpoofing is when a process or entity is something other than its claimed identity. Examples include substituting a process, a file, website or a network addressUserThreatDescriptionPhishing is attempted to obtain sensitive information such as usernames, passwords, and credit card details (and sometimes, indirectly, money), often for malicious reasons, by masquerading as a Web Server which is a trustworthy entity in electronic communicationInteractionStringPOST Add or Renew SubscriptionPossibleMitigationsVerify X.509 certificates used to authenticate SSL, TLS, and DTLS connections. Refer: <a href="https://aka.ms/tmtcommsec#x509-ssltls">https://aka.ms/tmtcommsec#x509-ssltls</a> Ensure that authenticated ASP.NET pages incorporate UI Redressing or clickjacking defences. Refer: <a href="https://aka.ms/tmtconfigmgmt#ui-defenses">https://aka.ms/tmtconfigmgmt#ui-defenses</a> Validate all redirects within the application are closed or done safely. Refer: <a href="https://aka.ms/tmtinputval#redirect-safe">https://aka.ms/tmtinputval#redirect-safe</a>PriorityHighSDLPhaseImplementation87952830-0247-4d6d-b43e-3e2f46f47ed0AutoGeneratedd37480d8-de0a-4967-b94c-81ace2b9f751TH81falsefalseTH8687952830-0247-4d6d-b43e-3e2f46f47ed06caed8a3-cf48-48ce-a144-01dd2ed39e44d37480d8-de0a-4967-b94c-81ace2b9f7515391df34-17a6-4ed9-87af-59d10800f0ee6caed8a3-cf48-48ce-a144-01dd2ed39e4422887952830-0247-4d6d-b43e-3e2f46f47ed0:6caed8a3-cf48-48ce-a144-01dd2ed39e44:d37480d8-de0a-4967-b94c-81ace2b9f7510001-01-01T00:00:00HighTitleAn adversary may spoof Browser and gain access to Web ApplicationUserThreatCategorySpoofingUserThreatShortDescriptionSpoofing is when a process or entity is something other than its claimed identity. Examples include substituting a process, a file, website or a network addressUserThreatDescriptionIf proper authentication is not in place, an adversary can spoof a source process or external entity and gain unauthorized access to the Web ApplicationInteractionStringPOST Add or Renew SubscriptionPossibleMitigationsConsider using a standard authentication mechanism to authenticate to Web Application. Refer: <a href="https://aka.ms/tmtauthn#standard-authn-web-app">https://aka.ms/tmtauthn#standard-authn-web-app</a>PriorityHighSDLPhaseDesign87952830-0247-4d6d-b43e-3e2f46f47ed0AutoGeneratedd37480d8-de0a-4967-b94c-81ace2b9f751TH86falsefalseTH2487952830-0247-4d6d-b43e-3e2f46f47ed06caed8a3-cf48-48ce-a144-01dd2ed39e44d37480d8-de0a-4967-b94c-81ace2b9f7515391df34-17a6-4ed9-87af-59d10800f0ee6caed8a3-cf48-48ce-a144-01dd2ed39e4422987952830-0247-4d6d-b43e-3e2f46f47ed0:6caed8a3-cf48-48ce-a144-01dd2ed39e44:d37480d8-de0a-4967-b94c-81ace2b9f7510001-01-01T00:00:00HighTitleAn adversary can deface the target web application by injecting malicious code or uploading dangerous filesUserThreatCategoryTamperingUserThreatShortDescriptionTampering is the act of altering the bits. Tampering with a process involves changing bits in the running process. Similarly, Tampering with a data flow involves changing bits on the wire or between two running processesUserThreatDescriptionWebsite defacement is an attack on a website where the attacker changes the visual appearance of the site or a webpage. InteractionStringPOST Add or Renew SubscriptionPossibleMitigationsImplement Content Security Policy (CSP), and disable inline javascript. Refer: <a href="https://aka.ms/tmtconfigmgmt#csp-js">https://aka.ms/tmtconfigmgmt#csp-js</a> Enable browser's XSS filter. Refer: <a href="https://aka.ms/tmtconfigmgmt#xss-filter">https://aka.ms/tmtconfigmgmt#xss-filter</a> Access third party javascripts from trusted sources only. Refer: <a href="https://aka.ms/tmtconfigmgmt#js-trusted">https://aka.ms/tmtconfigmgmt#js-trusted</a> Enable ValidateRequest attribute on ASP.NET Pages. Refer: <a href="https://aka.ms/tmtconfigmgmt#validate-aspnet">https://aka.ms/tmtconfigmgmt#validate-aspnet</a> Ensure that each page that could contain user controllable content opts out of automatic MIME sniffing . Refer: <a href="https://aka.ms/tmtinputval#out-sniffing">https://aka.ms/tmtinputval#out-sniffing</a> Use locally-hosted latest versions of JavaScript libraries . Refer: <a href="https://aka.ms/tmtconfigmgmt#local-js">https://aka.ms/tmtconfigmgmt#local-js</a> Ensure appropriate controls are in place when accepting files from users. Refer: <a href="https://aka.ms/tmtinputval#controls-users">https://aka.ms/tmtinputval#controls-users</a> Disable automatic MIME sniffing. Refer: <a href="https://aka.ms/tmtconfigmgmt#mime-sniff">https://aka.ms/tmtconfigmgmt#mime-sniff</a> Encode untrusted web output prior to rendering. Refer: <a href="https://aka.ms/tmtinputval#rendering">https://aka.ms/tmtinputval#rendering</a> Perform input validation and filtering on all string type Model properties. Refer: <a href="https://aka.ms/tmtinputval#typemodel">https://aka.ms/tmtinputval#typemodel</a> Ensure that the system has inbuilt defences against misuse. Refer: <a href="https://aka.ms/tmtauditlog#inbuilt-defenses">https://aka.ms/tmtauditlog#inbuilt-defenses</a> Enable HTTP Strict Transport Security (HSTS). Refer: <a href="https://aka.ms/tmtcommsec#http-hsts">https://aka.ms/tmtcommsec#http-hsts</a> Implement input validation on all string type parameters accepted by Controller methods. Refer: <a href="https://aka.ms/tmtinputval#string-method">https://aka.ms/tmtinputval#string-method</a> Avoid using Html.Raw in Razor views. Refer: <a href="https://aka.ms/tmtinputval#html-razor">https://aka.ms/tmtinputval#html-razor</a> Sanitization should be applied on form fields that accept all characters e.g, rich text editor . Refer: <a href="https://aka.ms/tmtinputval#richtext">https://aka.ms/tmtinputval#richtext</a> Do not assign DOM elements to sinks that do not have inbuilt encoding . Refer: <a href="https://aka.ms/tmtinputval#inbuilt-encode">https://aka.ms/tmtinputval#inbuilt-encode</a>PriorityHighSDLPhaseImplementation87952830-0247-4d6d-b43e-3e2f46f47ed0AutoGeneratedd37480d8-de0a-4967-b94c-81ace2b9f751TH24falsefalseTH3387952830-0247-4d6d-b43e-3e2f46f47ed06caed8a3-cf48-48ce-a144-01dd2ed39e44d37480d8-de0a-4967-b94c-81ace2b9f7515391df34-17a6-4ed9-87af-59d10800f0ee6caed8a3-cf48-48ce-a144-01dd2ed39e4423087952830-0247-4d6d-b43e-3e2f46f47ed0:6caed8a3-cf48-48ce-a144-01dd2ed39e44:d37480d8-de0a-4967-b94c-81ace2b9f7510001-01-01T00:00:00HighTitleAn attacker steals messages off the network and replays them in order to steal a user's sessionUserThreatCategoryTamperingUserThreatShortDescriptionTampering is the act of altering the bits. Tampering with a process involves changing bits in the running process. Similarly, Tampering with a data flow involves changing bits on the wire or between two running processesUserThreatDescriptionAn attacker steals messages off the network and replays them in order to steal a user's sessionInteractionStringPOST Add or Renew SubscriptionPriorityHighSDLPhaseImplementation87952830-0247-4d6d-b43e-3e2f46f47ed0AutoGeneratedd37480d8-de0a-4967-b94c-81ace2b9f751TH33falsefalseTH9687952830-0247-4d6d-b43e-3e2f46f47ed06caed8a3-cf48-48ce-a144-01dd2ed39e44d37480d8-de0a-4967-b94c-81ace2b9f7515391df34-17a6-4ed9-87af-59d10800f0ee6caed8a3-cf48-48ce-a144-01dd2ed39e4423187952830-0247-4d6d-b43e-3e2f46f47ed0:6caed8a3-cf48-48ce-a144-01dd2ed39e44:d37480d8-de0a-4967-b94c-81ace2b9f7510001-01-01T00:00:00HighTitleAn adversary can gain access to sensitive data by performing SQL injection through Web AppUserThreatCategoryTamperingUserThreatShortDescriptionTampering is the act of altering the bits. Tampering with a process involves changing bits in the running process. Similarly, Tampering with a data flow involves changing bits on the wire or between two running processesUserThreatDescriptionSQL injection is an attack in which malicious code is inserted into strings that are later passed to an instance of SQL Server for parsing and execution. The primary form of SQL injection consists of direct insertion of code into user-input variables that are concatenated with SQL commands and executed. A less direct attack injects malicious code into strings that are destined for storage in a table or as metadata. When the stored strings are subsequently concatenated into a dynamic SQL command, the malicious code is executed. InteractionStringPOST Add or Renew SubscriptionPossibleMitigationsEnsure that type-safe parameters are used in Web Application for data access. Refer: <a href="https://aka.ms/tmtinputval#typesafe">https://aka.ms/tmtinputval#typesafe</a>PriorityHighSDLPhaseImplementation87952830-0247-4d6d-b43e-3e2f46f47ed0AutoGeneratedd37480d8-de0a-4967-b94c-81ace2b9f751TH96falsefalseTH9887952830-0247-4d6d-b43e-3e2f46f47ed06caed8a3-cf48-48ce-a144-01dd2ed39e44d37480d8-de0a-4967-b94c-81ace2b9f7515391df34-17a6-4ed9-87af-59d10800f0ee6caed8a3-cf48-48ce-a144-01dd2ed39e4423287952830-0247-4d6d-b43e-3e2f46f47ed0:6caed8a3-cf48-48ce-a144-01dd2ed39e44:d37480d8-de0a-4967-b94c-81ace2b9f7510001-01-01T00:00:00HighTitleAn adversary can gain access to sensitive data stored in Web App's config filesUserThreatCategoryTamperingUserThreatShortDescriptionTampering is the act of altering the bits. Tampering with a process involves changing bits in the running process. Similarly, Tampering with a data flow involves changing bits on the wire or between two running processesUserThreatDescriptionAn adversary can gain access to the config files. and if sensitive data is stored in it, it would be compromised.InteractionStringPOST Add or Renew SubscriptionPossibleMitigationsEncrypt sections of Web App's configuration files that contain sensitive data. Refer: <a href="https://aka.ms/tmtdata#encrypt-data">https://aka.ms/tmtdata#encrypt-data</a>PriorityHighSDLPhaseImplementation87952830-0247-4d6d-b43e-3e2f46f47ed0AutoGeneratedd37480d8-de0a-4967-b94c-81ace2b9f751TH98falsefalseTH2687952830-0247-4d6d-b43e-3e2f46f47ed0d682bc87-20a8-4db1-b3c4-226a07278aa3d37480d8-de0a-4967-b94c-81ace2b9f7515391df34-17a6-4ed9-87af-59d10800f0eed682bc87-20a8-4db1-b3c4-226a07278aa323387952830-0247-4d6d-b43e-3e2f46f47ed0:d682bc87-20a8-4db1-b3c4-226a07278aa3:d37480d8-de0a-4967-b94c-81ace2b9f7510001-01-01T00:00:00HighTitleAn adversary can perform action on behalf of other user due to lack of controls against cross domain requestsUserThreatCategoryDenial of ServiceUserThreatShortDescriptionDenial of Service happens when the process or a datastore is not able to service incoming requests or perform up to specUserThreatDescriptionFailure to restrict requests originating from third party domains may result in unauthorized actions or access of dataInteractionStringGET SubscriptionPossibleMitigationsEnsure that authenticated ASP.NET pages incorporate UI Redressing or clickjacking defences. Refer: <a href="https://aka.ms/tmtconfigmgmt#ui-defenses">https://aka.ms/tmtconfigmgmt#ui-defenses</a> Ensure that only trusted origins are allowed if CORS is enabled on ASP.NET Web Applications. Refer: <a href="https://aka.ms/tmtconfigmgmt#cors-aspnet">https://aka.ms/tmtconfigmgmt#cors-aspnet</a> Mitigate against Cross-Site Request Forgery (CSRF) attacks on ASP.NET web pages. Refer: <a href="https://aka.ms/tmtsmgmt#csrf-asp">https://aka.ms/tmtsmgmt#csrf-asp</a>PriorityHighSDLPhaseImplementation87952830-0247-4d6d-b43e-3e2f46f47ed0AutoGeneratedd37480d8-de0a-4967-b94c-81ace2b9f751TH26falsefalseTH2787952830-0247-4d6d-b43e-3e2f46f47ed0d682bc87-20a8-4db1-b3c4-226a07278aa3d37480d8-de0a-4967-b94c-81ace2b9f7515391df34-17a6-4ed9-87af-59d10800f0eed682bc87-20a8-4db1-b3c4-226a07278aa323487952830-0247-4d6d-b43e-3e2f46f47ed0:d682bc87-20a8-4db1-b3c4-226a07278aa3:d37480d8-de0a-4967-b94c-81ace2b9f7510001-01-01T00:00:00HighTitleAn adversary may bypass critical steps or perform actions on behalf of other users (victims) due to improper validation logicUserThreatCategoryElevation of PrivilegesUserThreatShortDescriptionA user subject gains increased capability or privilege by taking advantage of an implementation bugUserThreatDescriptionFailure to restrict the privileges and access rights to the application to individuals who require the privileges or access rights may result into unauthorized use of data due to inappropriate rights settings and validation.InteractionStringGET SubscriptionPossibleMitigationsEnsure that administrative interfaces are appropriately locked down. Refer: <a href="https://aka.ms/tmtauthn#admin-interface-lockdown">https://aka.ms/tmtauthn#admin-interface-lockdown</a> Enforce sequential step order when processing business logic flows. Refer: <a href="https://aka.ms/tmtauthz#sequential-logic">https://aka.ms/tmtauthz#sequential-logic</a> Ensure that proper authorization is in place and principle of least privileges is followed. Refer: <a href="https://aka.ms/tmtauthz#principle-least-privilege">https://aka.ms/tmtauthz#principle-least-privilege</a> Business logic and resource access authorization decisions should not be based on incoming request parameters. Refer: <a href="https://aka.ms/tmtauthz#logic-request-parameters">https://aka.ms/tmtauthz#logic-request-parameters</a> Ensure that content and resources are not enumerable or accessible via forceful browsing. Refer: <a href="https://aka.ms/tmtauthz#enumerable-browsing">https://aka.ms/tmtauthz#enumerable-browsing</a>PriorityHighSDLPhaseImplementation87952830-0247-4d6d-b43e-3e2f46f47ed0AutoGeneratedd37480d8-de0a-4967-b94c-81ace2b9f751TH27falsefalseTH10187952830-0247-4d6d-b43e-3e2f46f47ed0d682bc87-20a8-4db1-b3c4-226a07278aa3d37480d8-de0a-4967-b94c-81ace2b9f7515391df34-17a6-4ed9-87af-59d10800f0eed682bc87-20a8-4db1-b3c4-226a07278aa323587952830-0247-4d6d-b43e-3e2f46f47ed0:d682bc87-20a8-4db1-b3c4-226a07278aa3:d37480d8-de0a-4967-b94c-81ace2b9f7510001-01-01T00:00:00HighTitleAn adversary can reverse weakly encrypted or hashed contentUserThreatCategoryInformation DisclosureUserThreatShortDescriptionInformation disclosure happens when the information can be read by an unauthorized partyUserThreatDescriptionAn adversary can reverse weakly encrypted or hashed contentInteractionStringGET SubscriptionPossibleMitigationsDo not expose security details in error messages. Refer: <a href="https://aka.ms/tmtxmgmt#messages">https://aka.ms/tmtxmgmt#messages</a> Implement Default error handling page. Refer: <a href="https://aka.ms/tmtxmgmt#default">https://aka.ms/tmtxmgmt#default</a> Set Deployment Method to Retail in IIS. Refer: <a href="https://aka.ms/tmtxmgmt#deployment">https://aka.ms/tmtxmgmt#deployment</a> Use only approved symmetric block ciphers and key lengths. Refer: <a href="https://aka.ms/tmtcrypto#cipher-length">https://aka.ms/tmtcrypto#cipher-length</a> Use approved block cipher modes and initialization vectors for symmetric ciphers. Refer: <a href="https://aka.ms/tmtcrypto#vector-ciphers">https://aka.ms/tmtcrypto#vector-ciphers</a> Use approved asymmetric algorithms, key lengths, and padding. Refer: <a href="https://aka.ms/tmtcrypto#padding">https://aka.ms/tmtcrypto#padding</a> Use approved random number generators. Refer: <a href="https://aka.ms/tmtcrypto#numgen">https://aka.ms/tmtcrypto#numgen</a> Do not use symmetric stream ciphers. Refer: <a href="https://aka.ms/tmtcrypto#stream-ciphers">https://aka.ms/tmtcrypto#stream-ciphers</a> Use approved MAC/HMAC/keyed hash algorithms. Refer: <a href="https://aka.ms/tmtcrypto#mac-hash">https://aka.ms/tmtcrypto#mac-hash</a> Use only approved cryptographic hash functions. Refer: <a href="https://aka.ms/tmtcrypto#hash-functions">https://aka.ms/tmtcrypto#hash-functions</a> Verify X.509 certificates used to authenticate SSL, TLS, and DTLS connections. Refer: <a href="https://aka.ms/tmtcommsec#x509-ssltls">https://aka.ms/tmtcommsec#x509-ssltls</a>PriorityHighSDLPhaseImplementation87952830-0247-4d6d-b43e-3e2f46f47ed0AutoGeneratedd37480d8-de0a-4967-b94c-81ace2b9f751TH101falsefalseTH10287952830-0247-4d6d-b43e-3e2f46f47ed0d682bc87-20a8-4db1-b3c4-226a07278aa3d37480d8-de0a-4967-b94c-81ace2b9f7515391df34-17a6-4ed9-87af-59d10800f0eed682bc87-20a8-4db1-b3c4-226a07278aa323687952830-0247-4d6d-b43e-3e2f46f47ed0:d682bc87-20a8-4db1-b3c4-226a07278aa3:d37480d8-de0a-4967-b94c-81ace2b9f7510001-01-01T00:00:00HighTitleAn adversary may gain access to sensitive data from log filesUserThreatCategoryInformation DisclosureUserThreatShortDescriptionInformation disclosure happens when the information can be read by an unauthorized partyUserThreatDescriptionAn adversary may gain access to sensitive data from log filesInteractionStringGET SubscriptionPossibleMitigationsEnsure that the application does not log sensitive user data. Refer: <a href="https://aka.ms/tmtauditlog#log-sensitive-data">https://aka.ms/tmtauditlog#log-sensitive-data</a> Ensure that Audit and Log Files have Restricted Access. Refer: <a href="https://aka.ms/tmtauditlog#log-restricted-access">https://aka.ms/tmtauditlog#log-restricted-access</a>PriorityHighSDLPhaseImplementation87952830-0247-4d6d-b43e-3e2f46f47ed0AutoGeneratedd37480d8-de0a-4967-b94c-81ace2b9f751TH102falsefalseTH10387952830-0247-4d6d-b43e-3e2f46f47ed0d682bc87-20a8-4db1-b3c4-226a07278aa3d37480d8-de0a-4967-b94c-81ace2b9f7515391df34-17a6-4ed9-87af-59d10800f0eed682bc87-20a8-4db1-b3c4-226a07278aa323787952830-0247-4d6d-b43e-3e2f46f47ed0:d682bc87-20a8-4db1-b3c4-226a07278aa3:d37480d8-de0a-4967-b94c-81ace2b9f7510001-01-01T00:00:00HighTitleAn adversary may gain access to unmasked sensitive data such as credit card numbersUserThreatCategoryInformation DisclosureUserThreatShortDescriptionInformation disclosure happens when the information can be read by an unauthorized partyUserThreatDescriptionAn adversary may gain access to unmasked sensitive data such as credit card numbersInteractionStringGET SubscriptionPossibleMitigationsEnsure that sensitive data displayed on the user screen is masked. Refer: <a href="https://aka.ms/tmtdata#data-mask">https://aka.ms/tmtdata#data-mask</a>PriorityHighSDLPhaseImplementation87952830-0247-4d6d-b43e-3e2f46f47ed0AutoGeneratedd37480d8-de0a-4967-b94c-81ace2b9f751TH103falsefalseTH8087952830-0247-4d6d-b43e-3e2f46f47ed0d682bc87-20a8-4db1-b3c4-226a07278aa3d37480d8-de0a-4967-b94c-81ace2b9f7515391df34-17a6-4ed9-87af-59d10800f0eed682bc87-20a8-4db1-b3c4-226a07278aa323887952830-0247-4d6d-b43e-3e2f46f47ed0:d682bc87-20a8-4db1-b3c4-226a07278aa3:d37480d8-de0a-4967-b94c-81ace2b9f7510001-01-01T00:00:00MediumTitleAn adversary can gain access to certain pages or the site as a whole.UserThreatCategoryInformation DisclosureUserThreatShortDescriptionInformation disclosure happens when the information can be read by an unauthorized partyUserThreatDescriptionRobots.txt is often found in your site's root directory and exists to regulate the bots that crawl your site. This is where you can grant or deny permission to all or some specific search engine robots to access certain pages or your site as a whole. The standard for this file was developed in 1994 and is known as the Robots Exclusion Standard or Robots Exclusion Protocol. Detailed info about the robots.txt protocol can be found at robotstxt.org.InteractionStringGET SubscriptionPossibleMitigationsEnsure that administrative interfaces are appropriately locked down. Refer: <a href="https://aka.ms/tmtauthn#admin-interface-lockdown">https://aka.ms/tmtauthn#admin-interface-lockdown</a>PriorityMediumSDLPhaseImplementation87952830-0247-4d6d-b43e-3e2f46f47ed0AutoGeneratedd37480d8-de0a-4967-b94c-81ace2b9f751TH80falsefalseTH987952830-0247-4d6d-b43e-3e2f46f47ed0d682bc87-20a8-4db1-b3c4-226a07278aa3d37480d8-de0a-4967-b94c-81ace2b9f7515391df34-17a6-4ed9-87af-59d10800f0eed682bc87-20a8-4db1-b3c4-226a07278aa323987952830-0247-4d6d-b43e-3e2f46f47ed0:d682bc87-20a8-4db1-b3c4-226a07278aa3:d37480d8-de0a-4967-b94c-81ace2b9f7510001-01-01T00:00:00HighTitleAn adversary can gain access to sensitive data by sniffing traffic to Web ApplicationUserThreatCategoryInformation DisclosureUserThreatShortDescriptionInformation disclosure happens when the information can be read by an unauthorized partyUserThreatDescriptionAn adversary may conduct man in the middle attack and downgrade TLS connection to clear text protocol, or forcing browser communication to pass through a proxy server that he controls. This may happen because the application may use mixed content or HTTP Strict Transport Security policy is not ensured.InteractionStringGET SubscriptionPossibleMitigationsApplications available over HTTPS must use secure cookies. Refer: <a href="https://aka.ms/tmtsmgmt#https-secure-cookies">https://aka.ms/tmtsmgmt#https-secure-cookies</a> Enable HTTP Strict Transport Security (HSTS). Refer: <a href="https://aka.ms/tmtcommsec#http-hsts">https://aka.ms/tmtcommsec#http-hsts</a>PriorityHighSDLPhaseImplementation87952830-0247-4d6d-b43e-3e2f46f47ed0AutoGeneratedd37480d8-de0a-4967-b94c-81ace2b9f751TH9falsefalseTH9487952830-0247-4d6d-b43e-3e2f46f47ed0d682bc87-20a8-4db1-b3c4-226a07278aa3d37480d8-de0a-4967-b94c-81ace2b9f7515391df34-17a6-4ed9-87af-59d10800f0eed682bc87-20a8-4db1-b3c4-226a07278aa324087952830-0247-4d6d-b43e-3e2f46f47ed0:d682bc87-20a8-4db1-b3c4-226a07278aa3:d37480d8-de0a-4967-b94c-81ace2b9f7510001-01-01T00:00:00HighTitleAn adversary can gain access to sensitive information through error messagesUserThreatCategoryInformation DisclosureUserThreatShortDescriptionInformation disclosure happens when the information can be read by an unauthorized partyUserThreatDescriptionAn adversary can gain access to sensitive data such as the following, through verbose error messages - Server names - Connection strings - Usernames - Passwords - SQL procedures - Details of dynamic SQL failures - Stack trace and lines of code - Variables stored in memory - Drive and folder locations - Application install points - Host configuration settings - Other internal application details InteractionStringGET SubscriptionPossibleMitigationsDo not expose security details in error messages. Refer: <a href="https://aka.ms/tmtxmgmt#messages">https://aka.ms/tmtxmgmt#messages</a> Implement Default error handling page. Refer: <a href="https://aka.ms/tmtxmgmt#default">https://aka.ms/tmtxmgmt#default</a> Set Deployment Method to Retail in IIS. Refer: <a href="https://aka.ms/tmtxmgmt#deployment">https://aka.ms/tmtxmgmt#deployment</a> Exceptions should fail safely. Refer: <a href="https://aka.ms/tmtxmgmt#fail">https://aka.ms/tmtxmgmt#fail</a> ASP.NET applications must disable tracing and debugging prior to deployment. Refer: <a href="https://aka.ms/tmtconfigmgmt#trace-deploy">https://aka.ms/tmtconfigmgmt#trace-deploy</a> Implement controls to prevent username enumeration. Refer: <a href="https://aka.ms/tmtauthn#controls-username-enum">https://aka.ms/tmtauthn#controls-username-enum</a>PriorityHighSDLPhaseImplementation87952830-0247-4d6d-b43e-3e2f46f47ed0AutoGeneratedd37480d8-de0a-4967-b94c-81ace2b9f751TH94falsefalseTH9987952830-0247-4d6d-b43e-3e2f46f47ed0d682bc87-20a8-4db1-b3c4-226a07278aa3d37480d8-de0a-4967-b94c-81ace2b9f7515391df34-17a6-4ed9-87af-59d10800f0eed682bc87-20a8-4db1-b3c4-226a07278aa324187952830-0247-4d6d-b43e-3e2f46f47ed0:d682bc87-20a8-4db1-b3c4-226a07278aa3:d37480d8-de0a-4967-b94c-81ace2b9f7510001-01-01T00:00:00HighTitleAn adversary may gain access to sensitive data from uncleared browser cacheUserThreatCategoryInformation DisclosureUserThreatShortDescriptionInformation disclosure happens when the information can be read by an unauthorized partyUserThreatDescriptionAn adversary may gain access to sensitive data from uncleared browser cacheInteractionStringGET SubscriptionPossibleMitigationsEnsure that sensitive content is not cached on the browser. Refer: <a href="https://aka.ms/tmtdata#cache-browser">https://aka.ms/tmtdata#cache-browser</a>PriorityHighSDLPhaseImplementation87952830-0247-4d6d-b43e-3e2f46f47ed0AutoGeneratedd37480d8-de0a-4967-b94c-81ace2b9f751TH99falsefalseTH3087952830-0247-4d6d-b43e-3e2f46f47ed0d682bc87-20a8-4db1-b3c4-226a07278aa3d37480d8-de0a-4967-b94c-81ace2b9f7515391df34-17a6-4ed9-87af-59d10800f0eed682bc87-20a8-4db1-b3c4-226a07278aa324287952830-0247-4d6d-b43e-3e2f46f47ed0:d682bc87-20a8-4db1-b3c4-226a07278aa3:d37480d8-de0a-4967-b94c-81ace2b9f7510001-01-01T00:00:00MediumTitleAttacker can deny the malicious act and remove the attack foot prints leading to repudiation issuesUserThreatCategoryRepudiationUserThreatShortDescriptionRepudiation threats involve an adversary denying that something happenedUserThreatDescriptionProper logging of all security events and user actions builds traceability in a system and denies any possible repudiation issues. In the absence of proper auditing and logging controls, it would become impossible to implement any accountability in a systemInteractionStringGET SubscriptionPossibleMitigationsEnsure that auditing and logging is enforced on the application. Refer: <a href="https://aka.ms/tmtauditlog#auditing">https://aka.ms/tmtauditlog#auditing</a> Ensure that log rotation and separation are in place. Refer: <a href="https://aka.ms/tmtauditlog#log-rotation">https://aka.ms/tmtauditlog#log-rotation</a> Ensure that Audit and Log Files have Restricted Access. Refer: <a href="https://aka.ms/tmtauditlog#log-restricted-access">https://aka.ms/tmtauditlog#log-restricted-access</a> Ensure that User Management Events are Logged. Refer: <a href="https://aka.ms/tmtauditlog#user-management">https://aka.ms/tmtauditlog#user-management</a>PriorityMediumSDLPhaseImplementation87952830-0247-4d6d-b43e-3e2f46f47ed0AutoGeneratedd37480d8-de0a-4967-b94c-81ace2b9f751TH30falsefalseTH2287952830-0247-4d6d-b43e-3e2f46f47ed0d682bc87-20a8-4db1-b3c4-226a07278aa3d37480d8-de0a-4967-b94c-81ace2b9f7515391df34-17a6-4ed9-87af-59d10800f0eed682bc87-20a8-4db1-b3c4-226a07278aa324387952830-0247-4d6d-b43e-3e2f46f47ed0:d682bc87-20a8-4db1-b3c4-226a07278aa3:d37480d8-de0a-4967-b94c-81ace2b9f7510001-01-01T00:00:00HighTitleAn adversary can get access to a user's session due to improper logout and timeoutUserThreatCategorySpoofingUserThreatShortDescriptionSpoofing is when a process or entity is something other than its claimed identity. Examples include substituting a process, a file, website or a network addressUserThreatDescriptionThe session cookies is the identifier by which the server knows the identity of current user for each incoming request. If the attacker is able to steal the user token he would be able to access all user data and perform all actions on behalf of user.InteractionStringGET SubscriptionPossibleMitigationsSet up session for inactivity lifetime. Refer: <a href="https://aka.ms/tmtsmgmt#inactivity-lifetime">https://aka.ms/tmtsmgmt#inactivity-lifetime</a> Implement proper logout from the application. Refer: <a href="https://aka.ms/tmtsmgmt#proper-app-logout">https://aka.ms/tmtsmgmt#proper-app-logout</a>PriorityHighSDLPhaseImplementation87952830-0247-4d6d-b43e-3e2f46f47ed0AutoGeneratedd37480d8-de0a-4967-b94c-81ace2b9f751TH22falsefalseTH2387952830-0247-4d6d-b43e-3e2f46f47ed0d682bc87-20a8-4db1-b3c4-226a07278aa3d37480d8-de0a-4967-b94c-81ace2b9f7515391df34-17a6-4ed9-87af-59d10800f0eed682bc87-20a8-4db1-b3c4-226a07278aa324487952830-0247-4d6d-b43e-3e2f46f47ed0:d682bc87-20a8-4db1-b3c4-226a07278aa3:d37480d8-de0a-4967-b94c-81ace2b9f7510001-01-01T00:00:00HighTitleAn adversary can get access to a user's session due to insecure coding practicesUserThreatCategorySpoofingUserThreatShortDescriptionSpoofing is when a process or entity is something other than its claimed identity. Examples include substituting a process, a file, website or a network addressUserThreatDescriptionThe session cookies is the identifier by which the server knows the identity of current user for each incoming request. If the attacker is able to steal the user token he would be able to access all user data and perform all actions on behalf of user.InteractionStringGET SubscriptionPossibleMitigationsEnable ValidateRequest attribute on ASP.NET Pages. Refer: <a href="https://aka.ms/tmtconfigmgmt#validate-aspnet">https://aka.ms/tmtconfigmgmt#validate-aspnet</a> Encode untrusted web output prior to rendering. Refer: <a href="https://aka.ms/tmtinputval#rendering">https://aka.ms/tmtinputval#rendering</a> Avoid using Html.Raw in Razor views. Refer: <a href="https://aka.ms/tmtinputval#html-razor">https://aka.ms/tmtinputval#html-razor</a> Sanitization should be applied on form fields that accept all characters e.g, rich text editor . Refer: <a href="https://aka.ms/tmtinputval#richtext">https://aka.ms/tmtinputval#richtext</a> Do not assign DOM elements to sinks that do not have inbuilt encoding . Refer: <a href="https://aka.ms/tmtinputval#inbuilt-encode">https://aka.ms/tmtinputval#inbuilt-encode</a>PriorityHighSDLPhaseImplementation87952830-0247-4d6d-b43e-3e2f46f47ed0AutoGeneratedd37480d8-de0a-4967-b94c-81ace2b9f751TH23falsefalseTH3287952830-0247-4d6d-b43e-3e2f46f47ed0d682bc87-20a8-4db1-b3c4-226a07278aa3d37480d8-de0a-4967-b94c-81ace2b9f7515391df34-17a6-4ed9-87af-59d10800f0eed682bc87-20a8-4db1-b3c4-226a07278aa324587952830-0247-4d6d-b43e-3e2f46f47ed0:d682bc87-20a8-4db1-b3c4-226a07278aa3:d37480d8-de0a-4967-b94c-81ace2b9f7510001-01-01T00:00:00HighTitleAn adversary can spoof the target web application due to insecure TLS certificate configurationUserThreatCategorySpoofingUserThreatShortDescriptionSpoofing is when a process or entity is something other than its claimed identity. Examples include substituting a process, a file, website or a network addressUserThreatDescriptionEnsure that TLS certificate parameters are configured with correct valuesInteractionStringGET SubscriptionPossibleMitigationsVerify X.509 certificates used to authenticate SSL, TLS, and DTLS connections. Refer: <a href="https://aka.ms/tmtcommsec#x509-ssltls">https://aka.ms/tmtcommsec#x509-ssltls</a>PriorityHighSDLPhaseImplementation87952830-0247-4d6d-b43e-3e2f46f47ed0AutoGeneratedd37480d8-de0a-4967-b94c-81ace2b9f751TH32falsefalseTH787952830-0247-4d6d-b43e-3e2f46f47ed0d682bc87-20a8-4db1-b3c4-226a07278aa3d37480d8-de0a-4967-b94c-81ace2b9f7515391df34-17a6-4ed9-87af-59d10800f0eed682bc87-20a8-4db1-b3c4-226a07278aa324687952830-0247-4d6d-b43e-3e2f46f47ed0:d682bc87-20a8-4db1-b3c4-226a07278aa3:d37480d8-de0a-4967-b94c-81ace2b9f7510001-01-01T00:00:00HighTitleAn adversary can steal sensitive data like user credentialsUserThreatCategorySpoofingUserThreatShortDescriptionSpoofing is when a process or entity is something other than its claimed identity. Examples include substituting a process, a file, website or a network addressUserThreatDescriptionAttackers can exploit weaknesses in system to steal user credentials. Downstream and upstream components are often accessed by using credentials stored in configuration stores. Attackers may steal the upstream or downstream component credentials. Attackers may steal credentials if, Credentials are stored and sent in clear text, Weak input validation coupled with dynamic sql queries, Password retrieval mechanism are poor, InteractionStringGET SubscriptionPossibleMitigationsExplicitly disable the autocomplete HTML attribute in sensitive forms and inputs. Refer: <a href="https://aka.ms/tmtdata#autocomplete-input">https://aka.ms/tmtdata#autocomplete-input</a> Perform input validation and filtering on all string type Model properties. Refer: <a href="https://aka.ms/tmtinputval#typemodel">https://aka.ms/tmtinputval#typemodel</a> Validate all redirects within the application are closed or done safely. Refer: <a href="https://aka.ms/tmtinputval#redirect-safe">https://aka.ms/tmtinputval#redirect-safe</a> Enable step up or adaptive authentication. Refer: <a href="https://aka.ms/tmtauthn#step-up-adaptive-authn">https://aka.ms/tmtauthn#step-up-adaptive-authn</a> Implement forgot password functionalities securely. Refer: <a href="https://aka.ms/tmtauthn#forgot-pword-fxn">https://aka.ms/tmtauthn#forgot-pword-fxn</a> Ensure that password and account policy are implemented. Refer: <a href="https://aka.ms/tmtauthn#pword-account-policy">https://aka.ms/tmtauthn#pword-account-policy</a> Implement input validation on all string type parameters accepted by Controller methods. Refer: <a href="https://aka.ms/tmtinputval#string-method">https://aka.ms/tmtinputval#string-method</a>PriorityHighSDLPhaseImplementation87952830-0247-4d6d-b43e-3e2f46f47ed0AutoGeneratedd37480d8-de0a-4967-b94c-81ace2b9f751TH7falsefalseTH887952830-0247-4d6d-b43e-3e2f46f47ed0d682bc87-20a8-4db1-b3c4-226a07278aa3d37480d8-de0a-4967-b94c-81ace2b9f7515391df34-17a6-4ed9-87af-59d10800f0eed682bc87-20a8-4db1-b3c4-226a07278aa324787952830-0247-4d6d-b43e-3e2f46f47ed0:d682bc87-20a8-4db1-b3c4-226a07278aa3:d37480d8-de0a-4967-b94c-81ace2b9f7510001-01-01T00:00:00HighTitleAttackers can steal user session cookies due to insecure cookie attributesUserThreatCategorySpoofingUserThreatShortDescriptionSpoofing is when a process or entity is something other than its claimed identity. Examples include substituting a process, a file, website or a network addressUserThreatDescriptionThe session cookies is the identifier by which the server knows the identity of current user for each incoming request. If the attacker is able to steal the user token he would be able to access all user data and perform all actions on behalf of user. InteractionStringGET SubscriptionPossibleMitigationsApplications available over HTTPS must use secure cookies. Refer: <a href="https://aka.ms/tmtsmgmt#https-secure-cookies">https://aka.ms/tmtsmgmt#https-secure-cookies</a> All http based application should specify http only for cookie definition. Refer: <a href="https://aka.ms/tmtsmgmt#cookie-definition">https://aka.ms/tmtsmgmt#cookie-definition</a>PriorityHighSDLPhaseImplementation87952830-0247-4d6d-b43e-3e2f46f47ed0AutoGeneratedd37480d8-de0a-4967-b94c-81ace2b9f751TH8falsefalseTH8187952830-0247-4d6d-b43e-3e2f46f47ed0d682bc87-20a8-4db1-b3c4-226a07278aa3d37480d8-de0a-4967-b94c-81ace2b9f7515391df34-17a6-4ed9-87af-59d10800f0eed682bc87-20a8-4db1-b3c4-226a07278aa324887952830-0247-4d6d-b43e-3e2f46f47ed0:d682bc87-20a8-4db1-b3c4-226a07278aa3:d37480d8-de0a-4967-b94c-81ace2b9f7510001-01-01T00:00:00HighTitleAn adversary can create a fake website and launch phishing attacksUserThreatCategorySpoofingUserThreatShortDescriptionSpoofing is when a process or entity is something other than its claimed identity. Examples include substituting a process, a file, website or a network addressUserThreatDescriptionPhishing is attempted to obtain sensitive information such as usernames, passwords, and credit card details (and sometimes, indirectly, money), often for malicious reasons, by masquerading as a Web Server which is a trustworthy entity in electronic communicationInteractionStringGET SubscriptionPossibleMitigationsVerify X.509 certificates used to authenticate SSL, TLS, and DTLS connections. Refer: <a href="https://aka.ms/tmtcommsec#x509-ssltls">https://aka.ms/tmtcommsec#x509-ssltls</a> Ensure that authenticated ASP.NET pages incorporate UI Redressing or clickjacking defences. Refer: <a href="https://aka.ms/tmtconfigmgmt#ui-defenses">https://aka.ms/tmtconfigmgmt#ui-defenses</a> Validate all redirects within the application are closed or done safely. Refer: <a href="https://aka.ms/tmtinputval#redirect-safe">https://aka.ms/tmtinputval#redirect-safe</a>PriorityHighSDLPhaseImplementation87952830-0247-4d6d-b43e-3e2f46f47ed0AutoGeneratedd37480d8-de0a-4967-b94c-81ace2b9f751TH81falsefalseTH8687952830-0247-4d6d-b43e-3e2f46f47ed0d682bc87-20a8-4db1-b3c4-226a07278aa3d37480d8-de0a-4967-b94c-81ace2b9f7515391df34-17a6-4ed9-87af-59d10800f0eed682bc87-20a8-4db1-b3c4-226a07278aa324987952830-0247-4d6d-b43e-3e2f46f47ed0:d682bc87-20a8-4db1-b3c4-226a07278aa3:d37480d8-de0a-4967-b94c-81ace2b9f7510001-01-01T00:00:00HighTitleAn adversary may spoof Browser and gain access to Web ApplicationUserThreatCategorySpoofingUserThreatShortDescriptionSpoofing is when a process or entity is something other than its claimed identity. Examples include substituting a process, a file, website or a network addressUserThreatDescriptionIf proper authentication is not in place, an adversary can spoof a source process or external entity and gain unauthorized access to the Web ApplicationInteractionStringGET SubscriptionPossibleMitigationsConsider using a standard authentication mechanism to authenticate to Web Application. Refer: <a href="https://aka.ms/tmtauthn#standard-authn-web-app">https://aka.ms/tmtauthn#standard-authn-web-app</a>PriorityHighSDLPhaseDesign87952830-0247-4d6d-b43e-3e2f46f47ed0AutoGeneratedd37480d8-de0a-4967-b94c-81ace2b9f751TH86falsefalseTH2487952830-0247-4d6d-b43e-3e2f46f47ed0d682bc87-20a8-4db1-b3c4-226a07278aa3d37480d8-de0a-4967-b94c-81ace2b9f7515391df34-17a6-4ed9-87af-59d10800f0eed682bc87-20a8-4db1-b3c4-226a07278aa325087952830-0247-4d6d-b43e-3e2f46f47ed0:d682bc87-20a8-4db1-b3c4-226a07278aa3:d37480d8-de0a-4967-b94c-81ace2b9f7510001-01-01T00:00:00HighTitleAn adversary can deface the target web application by injecting malicious code or uploading dangerous filesUserThreatCategoryTamperingUserThreatShortDescriptionTampering is the act of altering the bits. Tampering with a process involves changing bits in the running process. Similarly, Tampering with a data flow involves changing bits on the wire or between two running processesUserThreatDescriptionWebsite defacement is an attack on a website where the attacker changes the visual appearance of the site or a webpage. InteractionStringGET SubscriptionPossibleMitigationsImplement Content Security Policy (CSP), and disable inline javascript. Refer: <a href="https://aka.ms/tmtconfigmgmt#csp-js">https://aka.ms/tmtconfigmgmt#csp-js</a> Enable browser's XSS filter. Refer: <a href="https://aka.ms/tmtconfigmgmt#xss-filter">https://aka.ms/tmtconfigmgmt#xss-filter</a> Access third party javascripts from trusted sources only. Refer: <a href="https://aka.ms/tmtconfigmgmt#js-trusted">https://aka.ms/tmtconfigmgmt#js-trusted</a> Enable ValidateRequest attribute on ASP.NET Pages. Refer: <a href="https://aka.ms/tmtconfigmgmt#validate-aspnet">https://aka.ms/tmtconfigmgmt#validate-aspnet</a> Ensure that each page that could contain user controllable content opts out of automatic MIME sniffing . Refer: <a href="https://aka.ms/tmtinputval#out-sniffing">https://aka.ms/tmtinputval#out-sniffing</a> Use locally-hosted latest versions of JavaScript libraries . Refer: <a href="https://aka.ms/tmtconfigmgmt#local-js">https://aka.ms/tmtconfigmgmt#local-js</a> Ensure appropriate controls are in place when accepting files from users. Refer: <a href="https://aka.ms/tmtinputval#controls-users">https://aka.ms/tmtinputval#controls-users</a> Disable automatic MIME sniffing. Refer: <a href="https://aka.ms/tmtconfigmgmt#mime-sniff">https://aka.ms/tmtconfigmgmt#mime-sniff</a> Encode untrusted web output prior to rendering. Refer: <a href="https://aka.ms/tmtinputval#rendering">https://aka.ms/tmtinputval#rendering</a> Perform input validation and filtering on all string type Model properties. Refer: <a href="https://aka.ms/tmtinputval#typemodel">https://aka.ms/tmtinputval#typemodel</a> Ensure that the system has inbuilt defences against misuse. Refer: <a href="https://aka.ms/tmtauditlog#inbuilt-defenses">https://aka.ms/tmtauditlog#inbuilt-defenses</a> Enable HTTP Strict Transport Security (HSTS). Refer: <a href="https://aka.ms/tmtcommsec#http-hsts">https://aka.ms/tmtcommsec#http-hsts</a> Implement input validation on all string type parameters accepted by Controller methods. Refer: <a href="https://aka.ms/tmtinputval#string-method">https://aka.ms/tmtinputval#string-method</a> Avoid using Html.Raw in Razor views. Refer: <a href="https://aka.ms/tmtinputval#html-razor">https://aka.ms/tmtinputval#html-razor</a> Sanitization should be applied on form fields that accept all characters e.g, rich text editor . Refer: <a href="https://aka.ms/tmtinputval#richtext">https://aka.ms/tmtinputval#richtext</a> Do not assign DOM elements to sinks that do not have inbuilt encoding . Refer: <a href="https://aka.ms/tmtinputval#inbuilt-encode">https://aka.ms/tmtinputval#inbuilt-encode</a>PriorityHighSDLPhaseImplementation87952830-0247-4d6d-b43e-3e2f46f47ed0AutoGeneratedd37480d8-de0a-4967-b94c-81ace2b9f751TH24falsefalseTH3387952830-0247-4d6d-b43e-3e2f46f47ed0d682bc87-20a8-4db1-b3c4-226a07278aa3d37480d8-de0a-4967-b94c-81ace2b9f7515391df34-17a6-4ed9-87af-59d10800f0eed682bc87-20a8-4db1-b3c4-226a07278aa325187952830-0247-4d6d-b43e-3e2f46f47ed0:d682bc87-20a8-4db1-b3c4-226a07278aa3:d37480d8-de0a-4967-b94c-81ace2b9f7510001-01-01T00:00:00HighTitleAn attacker steals messages off the network and replays them in order to steal a user's sessionUserThreatCategoryTamperingUserThreatShortDescriptionTampering is the act of altering the bits. Tampering with a process involves changing bits in the running process. Similarly, Tampering with a data flow involves changing bits on the wire or between two running processesUserThreatDescriptionAn attacker steals messages off the network and replays them in order to steal a user's sessionInteractionStringGET SubscriptionPriorityHighSDLPhaseImplementation87952830-0247-4d6d-b43e-3e2f46f47ed0AutoGeneratedd37480d8-de0a-4967-b94c-81ace2b9f751TH33falsefalseTH9687952830-0247-4d6d-b43e-3e2f46f47ed0d682bc87-20a8-4db1-b3c4-226a07278aa3d37480d8-de0a-4967-b94c-81ace2b9f7515391df34-17a6-4ed9-87af-59d10800f0eed682bc87-20a8-4db1-b3c4-226a07278aa325287952830-0247-4d6d-b43e-3e2f46f47ed0:d682bc87-20a8-4db1-b3c4-226a07278aa3:d37480d8-de0a-4967-b94c-81ace2b9f7510001-01-01T00:00:00HighTitleAn adversary can gain access to sensitive data by performing SQL injection through Web AppUserThreatCategoryTamperingUserThreatShortDescriptionTampering is the act of altering the bits. Tampering with a process involves changing bits in the running process. Similarly, Tampering with a data flow involves changing bits on the wire or between two running processesUserThreatDescriptionSQL injection is an attack in which malicious code is inserted into strings that are later passed to an instance of SQL Server for parsing and execution. The primary form of SQL injection consists of direct insertion of code into user-input variables that are concatenated with SQL commands and executed. A less direct attack injects malicious code into strings that are destined for storage in a table or as metadata. When the stored strings are subsequently concatenated into a dynamic SQL command, the malicious code is executed. InteractionStringGET SubscriptionPossibleMitigationsEnsure that type-safe parameters are used in Web Application for data access. Refer: <a href="https://aka.ms/tmtinputval#typesafe">https://aka.ms/tmtinputval#typesafe</a>PriorityHighSDLPhaseImplementation87952830-0247-4d6d-b43e-3e2f46f47ed0AutoGeneratedd37480d8-de0a-4967-b94c-81ace2b9f751TH96falsefalseTH9887952830-0247-4d6d-b43e-3e2f46f47ed0d682bc87-20a8-4db1-b3c4-226a07278aa3d37480d8-de0a-4967-b94c-81ace2b9f7515391df34-17a6-4ed9-87af-59d10800f0eed682bc87-20a8-4db1-b3c4-226a07278aa325387952830-0247-4d6d-b43e-3e2f46f47ed0:d682bc87-20a8-4db1-b3c4-226a07278aa3:d37480d8-de0a-4967-b94c-81ace2b9f7510001-01-01T00:00:00HighTitleAn adversary can gain access to sensitive data stored in Web App's config filesUserThreatCategoryTamperingUserThreatShortDescriptionTampering is the act of altering the bits. Tampering with a process involves changing bits in the running process. Similarly, Tampering with a data flow involves changing bits on the wire or between two running processesUserThreatDescriptionAn adversary can gain access to the config files. and if sensitive data is stored in it, it would be compromised.InteractionStringGET SubscriptionPossibleMitigationsEncrypt sections of Web App's configuration files that contain sensitive data. Refer: <a href="https://aka.ms/tmtdata#encrypt-data">https://aka.ms/tmtdata#encrypt-data</a>PriorityHighSDLPhaseImplementation87952830-0247-4d6d-b43e-3e2f46f47ed0AutoGeneratedd37480d8-de0a-4967-b94c-81ace2b9f751TH98falsefalseTH2687952830-0247-4d6d-b43e-3e2f46f47ed0117f99b4-6aba-4de8-babb-3e686b4faea9d37480d8-de0a-4967-b94c-81ace2b9f7515391df34-17a6-4ed9-87af-59d10800f0ee117f99b4-6aba-4de8-babb-3e686b4faea925487952830-0247-4d6d-b43e-3e2f46f47ed0:117f99b4-6aba-4de8-babb-3e686b4faea9:d37480d8-de0a-4967-b94c-81ace2b9f7510001-01-01T00:00:00HighTitleAn adversary can perform action on behalf of other user due to lack of controls against cross domain requestsUserThreatCategoryDenial of ServiceUserThreatShortDescriptionDenial of Service happens when the process or a datastore is not able to service incoming requests or perform up to specUserThreatDescriptionFailure to restrict requests originating from third party domains may result in unauthorized actions or access of dataInteractionStringPOST Manually Process Call-IdPossibleMitigationsEnsure that authenticated ASP.NET pages incorporate UI Redressing or clickjacking defences. Refer: <a href="https://aka.ms/tmtconfigmgmt#ui-defenses">https://aka.ms/tmtconfigmgmt#ui-defenses</a> Ensure that only trusted origins are allowed if CORS is enabled on ASP.NET Web Applications. Refer: <a href="https://aka.ms/tmtconfigmgmt#cors-aspnet">https://aka.ms/tmtconfigmgmt#cors-aspnet</a> Mitigate against Cross-Site Request Forgery (CSRF) attacks on ASP.NET web pages. Refer: <a href="https://aka.ms/tmtsmgmt#csrf-asp">https://aka.ms/tmtsmgmt#csrf-asp</a>PriorityHighSDLPhaseImplementation87952830-0247-4d6d-b43e-3e2f46f47ed0AutoGeneratedd37480d8-de0a-4967-b94c-81ace2b9f751TH26falsefalseTH2787952830-0247-4d6d-b43e-3e2f46f47ed0117f99b4-6aba-4de8-babb-3e686b4faea9d37480d8-de0a-4967-b94c-81ace2b9f7515391df34-17a6-4ed9-87af-59d10800f0ee117f99b4-6aba-4de8-babb-3e686b4faea925587952830-0247-4d6d-b43e-3e2f46f47ed0:117f99b4-6aba-4de8-babb-3e686b4faea9:d37480d8-de0a-4967-b94c-81ace2b9f7510001-01-01T00:00:00HighTitleAn adversary may bypass critical steps or perform actions on behalf of other users (victims) due to improper validation logicUserThreatCategoryElevation of PrivilegesUserThreatShortDescriptionA user subject gains increased capability or privilege by taking advantage of an implementation bugUserThreatDescriptionFailure to restrict the privileges and access rights to the application to individuals who require the privileges or access rights may result into unauthorized use of data due to inappropriate rights settings and validation.InteractionStringPOST Manually Process Call-IdPossibleMitigationsEnsure that administrative interfaces are appropriately locked down. Refer: <a href="https://aka.ms/tmtauthn#admin-interface-lockdown">https://aka.ms/tmtauthn#admin-interface-lockdown</a> Enforce sequential step order when processing business logic flows. Refer: <a href="https://aka.ms/tmtauthz#sequential-logic">https://aka.ms/tmtauthz#sequential-logic</a> Ensure that proper authorization is in place and principle of least privileges is followed. Refer: <a href="https://aka.ms/tmtauthz#principle-least-privilege">https://aka.ms/tmtauthz#principle-least-privilege</a> Business logic and resource access authorization decisions should not be based on incoming request parameters. Refer: <a href="https://aka.ms/tmtauthz#logic-request-parameters">https://aka.ms/tmtauthz#logic-request-parameters</a> Ensure that content and resources are not enumerable or accessible via forceful browsing. Refer: <a href="https://aka.ms/tmtauthz#enumerable-browsing">https://aka.ms/tmtauthz#enumerable-browsing</a>PriorityHighSDLPhaseImplementation87952830-0247-4d6d-b43e-3e2f46f47ed0AutoGeneratedd37480d8-de0a-4967-b94c-81ace2b9f751TH27falsefalseTH10187952830-0247-4d6d-b43e-3e2f46f47ed0117f99b4-6aba-4de8-babb-3e686b4faea9d37480d8-de0a-4967-b94c-81ace2b9f7515391df34-17a6-4ed9-87af-59d10800f0ee117f99b4-6aba-4de8-babb-3e686b4faea925687952830-0247-4d6d-b43e-3e2f46f47ed0:117f99b4-6aba-4de8-babb-3e686b4faea9:d37480d8-de0a-4967-b94c-81ace2b9f7510001-01-01T00:00:00HighTitleAn adversary can reverse weakly encrypted or hashed contentUserThreatCategoryInformation DisclosureUserThreatShortDescriptionInformation disclosure happens when the information can be read by an unauthorized partyUserThreatDescriptionAn adversary can reverse weakly encrypted or hashed contentInteractionStringPOST Manually Process Call-IdPossibleMitigationsDo not expose security details in error messages. Refer: <a href="https://aka.ms/tmtxmgmt#messages">https://aka.ms/tmtxmgmt#messages</a> Implement Default error handling page. Refer: <a href="https://aka.ms/tmtxmgmt#default">https://aka.ms/tmtxmgmt#default</a> Set Deployment Method to Retail in IIS. Refer: <a href="https://aka.ms/tmtxmgmt#deployment">https://aka.ms/tmtxmgmt#deployment</a> Use only approved symmetric block ciphers and key lengths. Refer: <a href="https://aka.ms/tmtcrypto#cipher-length">https://aka.ms/tmtcrypto#cipher-length</a> Use approved block cipher modes and initialization vectors for symmetric ciphers. Refer: <a href="https://aka.ms/tmtcrypto#vector-ciphers">https://aka.ms/tmtcrypto#vector-ciphers</a> Use approved asymmetric algorithms, key lengths, and padding. Refer: <a href="https://aka.ms/tmtcrypto#padding">https://aka.ms/tmtcrypto#padding</a> Use approved random number generators. Refer: <a href="https://aka.ms/tmtcrypto#numgen">https://aka.ms/tmtcrypto#numgen</a> Do not use symmetric stream ciphers. Refer: <a href="https://aka.ms/tmtcrypto#stream-ciphers">https://aka.ms/tmtcrypto#stream-ciphers</a> Use approved MAC/HMAC/keyed hash algorithms. Refer: <a href="https://aka.ms/tmtcrypto#mac-hash">https://aka.ms/tmtcrypto#mac-hash</a> Use only approved cryptographic hash functions. Refer: <a href="https://aka.ms/tmtcrypto#hash-functions">https://aka.ms/tmtcrypto#hash-functions</a> Verify X.509 certificates used to authenticate SSL, TLS, and DTLS connections. Refer: <a href="https://aka.ms/tmtcommsec#x509-ssltls">https://aka.ms/tmtcommsec#x509-ssltls</a>PriorityHighSDLPhaseImplementation87952830-0247-4d6d-b43e-3e2f46f47ed0AutoGeneratedd37480d8-de0a-4967-b94c-81ace2b9f751TH101falsefalseTH10287952830-0247-4d6d-b43e-3e2f46f47ed0117f99b4-6aba-4de8-babb-3e686b4faea9d37480d8-de0a-4967-b94c-81ace2b9f7515391df34-17a6-4ed9-87af-59d10800f0ee117f99b4-6aba-4de8-babb-3e686b4faea925787952830-0247-4d6d-b43e-3e2f46f47ed0:117f99b4-6aba-4de8-babb-3e686b4faea9:d37480d8-de0a-4967-b94c-81ace2b9f7510001-01-01T00:00:00HighTitleAn adversary may gain access to sensitive data from log filesUserThreatCategoryInformation DisclosureUserThreatShortDescriptionInformation disclosure happens when the information can be read by an unauthorized partyUserThreatDescriptionAn adversary may gain access to sensitive data from log filesInteractionStringPOST Manually Process Call-IdPossibleMitigationsEnsure that the application does not log sensitive user data. Refer: <a href="https://aka.ms/tmtauditlog#log-sensitive-data">https://aka.ms/tmtauditlog#log-sensitive-data</a> Ensure that Audit and Log Files have Restricted Access. Refer: <a href="https://aka.ms/tmtauditlog#log-restricted-access">https://aka.ms/tmtauditlog#log-restricted-access</a>PriorityHighSDLPhaseImplementation87952830-0247-4d6d-b43e-3e2f46f47ed0AutoGeneratedd37480d8-de0a-4967-b94c-81ace2b9f751TH102falsefalseTH10387952830-0247-4d6d-b43e-3e2f46f47ed0117f99b4-6aba-4de8-babb-3e686b4faea9d37480d8-de0a-4967-b94c-81ace2b9f751REDMOND\justw5391df34-17a6-4ed9-87af-59d10800f0ee117f99b4-6aba-4de8-babb-3e686b4faea925887952830-0247-4d6d-b43e-3e2f46f47ed0:117f99b4-6aba-4de8-babb-3e686b4faea9:d37480d8-de0a-4967-b94c-81ace2b9f7512024-02-01T12:23:00.5832306-08:00HighTitleAn adversary may gain access to unmasked sensitive data such as credit card numbersUserThreatCategoryInformation DisclosureUserThreatShortDescriptionInformation disclosure happens when the information can be read by an unauthorized partyUserThreatDescriptionAn adversary may gain access to unmasked sensitive data such as credit card numbersInteractionStringPOST Manually Process Call-IdPossibleMitigationsEnsure that sensitive data displayed on the user screen is masked. Refer: <a href="https://aka.ms/tmtdata#data-mask">https://aka.ms/tmtdata#data-mask</a>PriorityHighSDLPhaseImplementation87952830-0247-4d6d-b43e-3e2f46f47ed0NotApplicabled37480d8-de0a-4967-b94c-81ace2b9f751TH103falsefalseTH8087952830-0247-4d6d-b43e-3e2f46f47ed0117f99b4-6aba-4de8-babb-3e686b4faea9d37480d8-de0a-4967-b94c-81ace2b9f7515391df34-17a6-4ed9-87af-59d10800f0ee117f99b4-6aba-4de8-babb-3e686b4faea925987952830-0247-4d6d-b43e-3e2f46f47ed0:117f99b4-6aba-4de8-babb-3e686b4faea9:d37480d8-de0a-4967-b94c-81ace2b9f7510001-01-01T00:00:00MediumTitleAn adversary can gain access to certain pages or the site as a whole.UserThreatCategoryInformation DisclosureUserThreatShortDescriptionInformation disclosure happens when the information can be read by an unauthorized partyUserThreatDescriptionRobots.txt is often found in your site's root directory and exists to regulate the bots that crawl your site. This is where you can grant or deny permission to all or some specific search engine robots to access certain pages or your site as a whole. The standard for this file was developed in 1994 and is known as the Robots Exclusion Standard or Robots Exclusion Protocol. Detailed info about the robots.txt protocol can be found at robotstxt.org.InteractionStringPOST Manually Process Call-IdPossibleMitigationsEnsure that administrative interfaces are appropriately locked down. Refer: <a href="https://aka.ms/tmtauthn#admin-interface-lockdown">https://aka.ms/tmtauthn#admin-interface-lockdown</a>PriorityMediumSDLPhaseImplementation87952830-0247-4d6d-b43e-3e2f46f47ed0AutoGeneratedd37480d8-de0a-4967-b94c-81ace2b9f751TH80falsefalseTH987952830-0247-4d6d-b43e-3e2f46f47ed0117f99b4-6aba-4de8-babb-3e686b4faea9d37480d8-de0a-4967-b94c-81ace2b9f7515391df34-17a6-4ed9-87af-59d10800f0ee117f99b4-6aba-4de8-babb-3e686b4faea926087952830-0247-4d6d-b43e-3e2f46f47ed0:117f99b4-6aba-4de8-babb-3e686b4faea9:d37480d8-de0a-4967-b94c-81ace2b9f7510001-01-01T00:00:00HighTitleAn adversary can gain access to sensitive data by sniffing traffic to Web ApplicationUserThreatCategoryInformation DisclosureUserThreatShortDescriptionInformation disclosure happens when the information can be read by an unauthorized partyUserThreatDescriptionAn adversary may conduct man in the middle attack and downgrade TLS connection to clear text protocol, or forcing browser communication to pass through a proxy server that he controls. This may happen because the application may use mixed content or HTTP Strict Transport Security policy is not ensured.InteractionStringPOST Manually Process Call-IdPossibleMitigationsApplications available over HTTPS must use secure cookies. Refer: <a href="https://aka.ms/tmtsmgmt#https-secure-cookies">https://aka.ms/tmtsmgmt#https-secure-cookies</a> Enable HTTP Strict Transport Security (HSTS). Refer: <a href="https://aka.ms/tmtcommsec#http-hsts">https://aka.ms/tmtcommsec#http-hsts</a>PriorityHighSDLPhaseImplementation87952830-0247-4d6d-b43e-3e2f46f47ed0AutoGeneratedd37480d8-de0a-4967-b94c-81ace2b9f751TH9falsefalseTH9487952830-0247-4d6d-b43e-3e2f46f47ed0117f99b4-6aba-4de8-babb-3e686b4faea9d37480d8-de0a-4967-b94c-81ace2b9f7515391df34-17a6-4ed9-87af-59d10800f0ee117f99b4-6aba-4de8-babb-3e686b4faea926187952830-0247-4d6d-b43e-3e2f46f47ed0:117f99b4-6aba-4de8-babb-3e686b4faea9:d37480d8-de0a-4967-b94c-81ace2b9f7510001-01-01T00:00:00HighTitleAn adversary can gain access to sensitive information through error messagesUserThreatCategoryInformation DisclosureUserThreatShortDescriptionInformation disclosure happens when the information can be read by an unauthorized partyUserThreatDescriptionAn adversary can gain access to sensitive data such as the following, through verbose error messages - Server names - Connection strings - Usernames - Passwords - SQL procedures - Details of dynamic SQL failures - Stack trace and lines of code - Variables stored in memory - Drive and folder locations - Application install points - Host configuration settings - Other internal application details InteractionStringPOST Manually Process Call-IdPossibleMitigationsDo not expose security details in error messages. Refer: <a href="https://aka.ms/tmtxmgmt#messages">https://aka.ms/tmtxmgmt#messages</a> Implement Default error handling page. Refer: <a href="https://aka.ms/tmtxmgmt#default">https://aka.ms/tmtxmgmt#default</a> Set Deployment Method to Retail in IIS. Refer: <a href="https://aka.ms/tmtxmgmt#deployment">https://aka.ms/tmtxmgmt#deployment</a> Exceptions should fail safely. Refer: <a href="https://aka.ms/tmtxmgmt#fail">https://aka.ms/tmtxmgmt#fail</a> ASP.NET applications must disable tracing and debugging prior to deployment. Refer: <a href="https://aka.ms/tmtconfigmgmt#trace-deploy">https://aka.ms/tmtconfigmgmt#trace-deploy</a> Implement controls to prevent username enumeration. Refer: <a href="https://aka.ms/tmtauthn#controls-username-enum">https://aka.ms/tmtauthn#controls-username-enum</a>PriorityHighSDLPhaseImplementation87952830-0247-4d6d-b43e-3e2f46f47ed0AutoGeneratedd37480d8-de0a-4967-b94c-81ace2b9f751TH94falsefalseTH9987952830-0247-4d6d-b43e-3e2f46f47ed0117f99b4-6aba-4de8-babb-3e686b4faea9d37480d8-de0a-4967-b94c-81ace2b9f7515391df34-17a6-4ed9-87af-59d10800f0ee117f99b4-6aba-4de8-babb-3e686b4faea926287952830-0247-4d6d-b43e-3e2f46f47ed0:117f99b4-6aba-4de8-babb-3e686b4faea9:d37480d8-de0a-4967-b94c-81ace2b9f7510001-01-01T00:00:00HighTitleAn adversary may gain access to sensitive data from uncleared browser cacheUserThreatCategoryInformation DisclosureUserThreatShortDescriptionInformation disclosure happens when the information can be read by an unauthorized partyUserThreatDescriptionAn adversary may gain access to sensitive data from uncleared browser cacheInteractionStringPOST Manually Process Call-IdPossibleMitigationsEnsure that sensitive content is not cached on the browser. Refer: <a href="https://aka.ms/tmtdata#cache-browser">https://aka.ms/tmtdata#cache-browser</a>PriorityHighSDLPhaseImplementation87952830-0247-4d6d-b43e-3e2f46f47ed0AutoGeneratedd37480d8-de0a-4967-b94c-81ace2b9f751TH99falsefalseTH3087952830-0247-4d6d-b43e-3e2f46f47ed0117f99b4-6aba-4de8-babb-3e686b4faea9d37480d8-de0a-4967-b94c-81ace2b9f7515391df34-17a6-4ed9-87af-59d10800f0ee117f99b4-6aba-4de8-babb-3e686b4faea926387952830-0247-4d6d-b43e-3e2f46f47ed0:117f99b4-6aba-4de8-babb-3e686b4faea9:d37480d8-de0a-4967-b94c-81ace2b9f7510001-01-01T00:00:00MediumTitleAttacker can deny the malicious act and remove the attack foot prints leading to repudiation issuesUserThreatCategoryRepudiationUserThreatShortDescriptionRepudiation threats involve an adversary denying that something happenedUserThreatDescriptionProper logging of all security events and user actions builds traceability in a system and denies any possible repudiation issues. In the absence of proper auditing and logging controls, it would become impossible to implement any accountability in a systemInteractionStringPOST Manually Process Call-IdPossibleMitigationsEnsure that auditing and logging is enforced on the application. Refer: <a href="https://aka.ms/tmtauditlog#auditing">https://aka.ms/tmtauditlog#auditing</a> Ensure that log rotation and separation are in place. Refer: <a href="https://aka.ms/tmtauditlog#log-rotation">https://aka.ms/tmtauditlog#log-rotation</a> Ensure that Audit and Log Files have Restricted Access. Refer: <a href="https://aka.ms/tmtauditlog#log-restricted-access">https://aka.ms/tmtauditlog#log-restricted-access</a> Ensure that User Management Events are Logged. Refer: <a href="https://aka.ms/tmtauditlog#user-management">https://aka.ms/tmtauditlog#user-management</a>PriorityMediumSDLPhaseImplementation87952830-0247-4d6d-b43e-3e2f46f47ed0AutoGeneratedd37480d8-de0a-4967-b94c-81ace2b9f751TH30falsefalseTH2287952830-0247-4d6d-b43e-3e2f46f47ed0117f99b4-6aba-4de8-babb-3e686b4faea9d37480d8-de0a-4967-b94c-81ace2b9f7515391df34-17a6-4ed9-87af-59d10800f0ee117f99b4-6aba-4de8-babb-3e686b4faea926487952830-0247-4d6d-b43e-3e2f46f47ed0:117f99b4-6aba-4de8-babb-3e686b4faea9:d37480d8-de0a-4967-b94c-81ace2b9f7510001-01-01T00:00:00HighTitleAn adversary can get access to a user's session due to improper logout and timeoutUserThreatCategorySpoofingUserThreatShortDescriptionSpoofing is when a process or entity is something other than its claimed identity. Examples include substituting a process, a file, website or a network addressUserThreatDescriptionThe session cookies is the identifier by which the server knows the identity of current user for each incoming request. If the attacker is able to steal the user token he would be able to access all user data and perform all actions on behalf of user.InteractionStringPOST Manually Process Call-IdPossibleMitigationsSet up session for inactivity lifetime. Refer: <a href="https://aka.ms/tmtsmgmt#inactivity-lifetime">https://aka.ms/tmtsmgmt#inactivity-lifetime</a> Implement proper logout from the application. Refer: <a href="https://aka.ms/tmtsmgmt#proper-app-logout">https://aka.ms/tmtsmgmt#proper-app-logout</a>PriorityHighSDLPhaseImplementation87952830-0247-4d6d-b43e-3e2f46f47ed0AutoGeneratedd37480d8-de0a-4967-b94c-81ace2b9f751TH22falsefalseTH2387952830-0247-4d6d-b43e-3e2f46f47ed0117f99b4-6aba-4de8-babb-3e686b4faea9d37480d8-de0a-4967-b94c-81ace2b9f7515391df34-17a6-4ed9-87af-59d10800f0ee117f99b4-6aba-4de8-babb-3e686b4faea926587952830-0247-4d6d-b43e-3e2f46f47ed0:117f99b4-6aba-4de8-babb-3e686b4faea9:d37480d8-de0a-4967-b94c-81ace2b9f7510001-01-01T00:00:00HighTitleAn adversary can get access to a user's session due to insecure coding practicesUserThreatCategorySpoofingUserThreatShortDescriptionSpoofing is when a process or entity is something other than its claimed identity. Examples include substituting a process, a file, website or a network addressUserThreatDescriptionThe session cookies is the identifier by which the server knows the identity of current user for each incoming request. If the attacker is able to steal the user token he would be able to access all user data and perform all actions on behalf of user.InteractionStringPOST Manually Process Call-IdPossibleMitigationsEnable ValidateRequest attribute on ASP.NET Pages. Refer: <a href="https://aka.ms/tmtconfigmgmt#validate-aspnet">https://aka.ms/tmtconfigmgmt#validate-aspnet</a> Encode untrusted web output prior to rendering. Refer: <a href="https://aka.ms/tmtinputval#rendering">https://aka.ms/tmtinputval#rendering</a> Avoid using Html.Raw in Razor views. Refer: <a href="https://aka.ms/tmtinputval#html-razor">https://aka.ms/tmtinputval#html-razor</a> Sanitization should be applied on form fields that accept all characters e.g, rich text editor . Refer: <a href="https://aka.ms/tmtinputval#richtext">https://aka.ms/tmtinputval#richtext</a> Do not assign DOM elements to sinks that do not have inbuilt encoding . Refer: <a href="https://aka.ms/tmtinputval#inbuilt-encode">https://aka.ms/tmtinputval#inbuilt-encode</a>PriorityHighSDLPhaseImplementation87952830-0247-4d6d-b43e-3e2f46f47ed0AutoGeneratedd37480d8-de0a-4967-b94c-81ace2b9f751TH23falsefalseTH3287952830-0247-4d6d-b43e-3e2f46f47ed0117f99b4-6aba-4de8-babb-3e686b4faea9d37480d8-de0a-4967-b94c-81ace2b9f7515391df34-17a6-4ed9-87af-59d10800f0ee117f99b4-6aba-4de8-babb-3e686b4faea926687952830-0247-4d6d-b43e-3e2f46f47ed0:117f99b4-6aba-4de8-babb-3e686b4faea9:d37480d8-de0a-4967-b94c-81ace2b9f7510001-01-01T00:00:00HighTitleAn adversary can spoof the target web application due to insecure TLS certificate configurationUserThreatCategorySpoofingUserThreatShortDescriptionSpoofing is when a process or entity is something other than its claimed identity. Examples include substituting a process, a file, website or a network addressUserThreatDescriptionEnsure that TLS certificate parameters are configured with correct valuesInteractionStringPOST Manually Process Call-IdPossibleMitigationsVerify X.509 certificates used to authenticate SSL, TLS, and DTLS connections. Refer: <a href="https://aka.ms/tmtcommsec#x509-ssltls">https://aka.ms/tmtcommsec#x509-ssltls</a>PriorityHighSDLPhaseImplementation87952830-0247-4d6d-b43e-3e2f46f47ed0AutoGeneratedd37480d8-de0a-4967-b94c-81ace2b9f751TH32falsefalseTH787952830-0247-4d6d-b43e-3e2f46f47ed0117f99b4-6aba-4de8-babb-3e686b4faea9d37480d8-de0a-4967-b94c-81ace2b9f7515391df34-17a6-4ed9-87af-59d10800f0ee117f99b4-6aba-4de8-babb-3e686b4faea926787952830-0247-4d6d-b43e-3e2f46f47ed0:117f99b4-6aba-4de8-babb-3e686b4faea9:d37480d8-de0a-4967-b94c-81ace2b9f7510001-01-01T00:00:00HighTitleAn adversary can steal sensitive data like user credentialsUserThreatCategorySpoofingUserThreatShortDescriptionSpoofing is when a process or entity is something other than its claimed identity. Examples include substituting a process, a file, website or a network addressUserThreatDescriptionAttackers can exploit weaknesses in system to steal user credentials. Downstream and upstream components are often accessed by using credentials stored in configuration stores. Attackers may steal the upstream or downstream component credentials. Attackers may steal credentials if, Credentials are stored and sent in clear text, Weak input validation coupled with dynamic sql queries, Password retrieval mechanism are poor, InteractionStringPOST Manually Process Call-IdPossibleMitigationsExplicitly disable the autocomplete HTML attribute in sensitive forms and inputs. Refer: <a href="https://aka.ms/tmtdata#autocomplete-input">https://aka.ms/tmtdata#autocomplete-input</a> Perform input validation and filtering on all string type Model properties. Refer: <a href="https://aka.ms/tmtinputval#typemodel">https://aka.ms/tmtinputval#typemodel</a> Validate all redirects within the application are closed or done safely. Refer: <a href="https://aka.ms/tmtinputval#redirect-safe">https://aka.ms/tmtinputval#redirect-safe</a> Enable step up or adaptive authentication. Refer: <a href="https://aka.ms/tmtauthn#step-up-adaptive-authn">https://aka.ms/tmtauthn#step-up-adaptive-authn</a> Implement forgot password functionalities securely. Refer: <a href="https://aka.ms/tmtauthn#forgot-pword-fxn">https://aka.ms/tmtauthn#forgot-pword-fxn</a> Ensure that password and account policy are implemented. Refer: <a href="https://aka.ms/tmtauthn#pword-account-policy">https://aka.ms/tmtauthn#pword-account-policy</a> Implement input validation on all string type parameters accepted by Controller methods. Refer: <a href="https://aka.ms/tmtinputval#string-method">https://aka.ms/tmtinputval#string-method</a>PriorityHighSDLPhaseImplementation87952830-0247-4d6d-b43e-3e2f46f47ed0AutoGeneratedd37480d8-de0a-4967-b94c-81ace2b9f751TH7falsefalseTH887952830-0247-4d6d-b43e-3e2f46f47ed0117f99b4-6aba-4de8-babb-3e686b4faea9d37480d8-de0a-4967-b94c-81ace2b9f7515391df34-17a6-4ed9-87af-59d10800f0ee117f99b4-6aba-4de8-babb-3e686b4faea926887952830-0247-4d6d-b43e-3e2f46f47ed0:117f99b4-6aba-4de8-babb-3e686b4faea9:d37480d8-de0a-4967-b94c-81ace2b9f7510001-01-01T00:00:00HighTitleAttackers can steal user session cookies due to insecure cookie attributesUserThreatCategorySpoofingUserThreatShortDescriptionSpoofing is when a process or entity is something other than its claimed identity. Examples include substituting a process, a file, website or a network addressUserThreatDescriptionThe session cookies is the identifier by which the server knows the identity of current user for each incoming request. If the attacker is able to steal the user token he would be able to access all user data and perform all actions on behalf of user. InteractionStringPOST Manually Process Call-IdPossibleMitigationsApplications available over HTTPS must use secure cookies. Refer: <a href="https://aka.ms/tmtsmgmt#https-secure-cookies">https://aka.ms/tmtsmgmt#https-secure-cookies</a> All http based application should specify http only for cookie definition. Refer: <a href="https://aka.ms/tmtsmgmt#cookie-definition">https://aka.ms/tmtsmgmt#cookie-definition</a>PriorityHighSDLPhaseImplementation87952830-0247-4d6d-b43e-3e2f46f47ed0AutoGeneratedd37480d8-de0a-4967-b94c-81ace2b9f751TH8falsefalseTH8187952830-0247-4d6d-b43e-3e2f46f47ed0117f99b4-6aba-4de8-babb-3e686b4faea9d37480d8-de0a-4967-b94c-81ace2b9f7515391df34-17a6-4ed9-87af-59d10800f0ee117f99b4-6aba-4de8-babb-3e686b4faea926987952830-0247-4d6d-b43e-3e2f46f47ed0:117f99b4-6aba-4de8-babb-3e686b4faea9:d37480d8-de0a-4967-b94c-81ace2b9f7510001-01-01T00:00:00HighTitleAn adversary can create a fake website and launch phishing attacksUserThreatCategorySpoofingUserThreatShortDescriptionSpoofing is when a process or entity is something other than its claimed identity. Examples include substituting a process, a file, website or a network addressUserThreatDescriptionPhishing is attempted to obtain sensitive information such as usernames, passwords, and credit card details (and sometimes, indirectly, money), often for malicious reasons, by masquerading as a Web Server which is a trustworthy entity in electronic communicationInteractionStringPOST Manually Process Call-IdPossibleMitigationsVerify X.509 certificates used to authenticate SSL, TLS, and DTLS connections. Refer: <a href="https://aka.ms/tmtcommsec#x509-ssltls">https://aka.ms/tmtcommsec#x509-ssltls</a> Ensure that authenticated ASP.NET pages incorporate UI Redressing or clickjacking defences. Refer: <a href="https://aka.ms/tmtconfigmgmt#ui-defenses">https://aka.ms/tmtconfigmgmt#ui-defenses</a> Validate all redirects within the application are closed or done safely. Refer: <a href="https://aka.ms/tmtinputval#redirect-safe">https://aka.ms/tmtinputval#redirect-safe</a>PriorityHighSDLPhaseImplementation87952830-0247-4d6d-b43e-3e2f46f47ed0AutoGeneratedd37480d8-de0a-4967-b94c-81ace2b9f751TH81falsefalseTH8687952830-0247-4d6d-b43e-3e2f46f47ed0117f99b4-6aba-4de8-babb-3e686b4faea9d37480d8-de0a-4967-b94c-81ace2b9f7515391df34-17a6-4ed9-87af-59d10800f0ee117f99b4-6aba-4de8-babb-3e686b4faea927087952830-0247-4d6d-b43e-3e2f46f47ed0:117f99b4-6aba-4de8-babb-3e686b4faea9:d37480d8-de0a-4967-b94c-81ace2b9f7510001-01-01T00:00:00HighTitleAn adversary may spoof Browser and gain access to Web ApplicationUserThreatCategorySpoofingUserThreatShortDescriptionSpoofing is when a process or entity is something other than its claimed identity. Examples include substituting a process, a file, website or a network addressUserThreatDescriptionIf proper authentication is not in place, an adversary can spoof a source process or external entity and gain unauthorized access to the Web ApplicationInteractionStringPOST Manually Process Call-IdPossibleMitigationsConsider using a standard authentication mechanism to authenticate to Web Application. Refer: <a href="https://aka.ms/tmtauthn#standard-authn-web-app">https://aka.ms/tmtauthn#standard-authn-web-app</a>PriorityHighSDLPhaseDesign87952830-0247-4d6d-b43e-3e2f46f47ed0AutoGeneratedd37480d8-de0a-4967-b94c-81ace2b9f751TH86falsefalseTH2487952830-0247-4d6d-b43e-3e2f46f47ed0117f99b4-6aba-4de8-babb-3e686b4faea9d37480d8-de0a-4967-b94c-81ace2b9f7515391df34-17a6-4ed9-87af-59d10800f0ee117f99b4-6aba-4de8-babb-3e686b4faea927187952830-0247-4d6d-b43e-3e2f46f47ed0:117f99b4-6aba-4de8-babb-3e686b4faea9:d37480d8-de0a-4967-b94c-81ace2b9f7510001-01-01T00:00:00HighTitleAn adversary can deface the target web application by injecting malicious code or uploading dangerous filesUserThreatCategoryTamperingUserThreatShortDescriptionTampering is the act of altering the bits. Tampering with a process involves changing bits in the running process. Similarly, Tampering with a data flow involves changing bits on the wire or between two running processesUserThreatDescriptionWebsite defacement is an attack on a website where the attacker changes the visual appearance of the site or a webpage. InteractionStringPOST Manually Process Call-IdPossibleMitigationsImplement Content Security Policy (CSP), and disable inline javascript. Refer: <a href="https://aka.ms/tmtconfigmgmt#csp-js">https://aka.ms/tmtconfigmgmt#csp-js</a> Enable browser's XSS filter. Refer: <a href="https://aka.ms/tmtconfigmgmt#xss-filter">https://aka.ms/tmtconfigmgmt#xss-filter</a> Access third party javascripts from trusted sources only. Refer: <a href="https://aka.ms/tmtconfigmgmt#js-trusted">https://aka.ms/tmtconfigmgmt#js-trusted</a> Enable ValidateRequest attribute on ASP.NET Pages. Refer: <a href="https://aka.ms/tmtconfigmgmt#validate-aspnet">https://aka.ms/tmtconfigmgmt#validate-aspnet</a> Ensure that each page that could contain user controllable content opts out of automatic MIME sniffing . Refer: <a href="https://aka.ms/tmtinputval#out-sniffing">https://aka.ms/tmtinputval#out-sniffing</a> Use locally-hosted latest versions of JavaScript libraries . Refer: <a href="https://aka.ms/tmtconfigmgmt#local-js">https://aka.ms/tmtconfigmgmt#local-js</a> Ensure appropriate controls are in place when accepting files from users. Refer: <a href="https://aka.ms/tmtinputval#controls-users">https://aka.ms/tmtinputval#controls-users</a> Disable automatic MIME sniffing. Refer: <a href="https://aka.ms/tmtconfigmgmt#mime-sniff">https://aka.ms/tmtconfigmgmt#mime-sniff</a> Encode untrusted web output prior to rendering. Refer: <a href="https://aka.ms/tmtinputval#rendering">https://aka.ms/tmtinputval#rendering</a> Perform input validation and filtering on all string type Model properties. Refer: <a href="https://aka.ms/tmtinputval#typemodel">https://aka.ms/tmtinputval#typemodel</a> Ensure that the system has inbuilt defences against misuse. Refer: <a href="https://aka.ms/tmtauditlog#inbuilt-defenses">https://aka.ms/tmtauditlog#inbuilt-defenses</a> Enable HTTP Strict Transport Security (HSTS). Refer: <a href="https://aka.ms/tmtcommsec#http-hsts">https://aka.ms/tmtcommsec#http-hsts</a> Implement input validation on all string type parameters accepted by Controller methods. Refer: <a href="https://aka.ms/tmtinputval#string-method">https://aka.ms/tmtinputval#string-method</a> Avoid using Html.Raw in Razor views. Refer: <a href="https://aka.ms/tmtinputval#html-razor">https://aka.ms/tmtinputval#html-razor</a> Sanitization should be applied on form fields that accept all characters e.g, rich text editor . Refer: <a href="https://aka.ms/tmtinputval#richtext">https://aka.ms/tmtinputval#richtext</a> Do not assign DOM elements to sinks that do not have inbuilt encoding . Refer: <a href="https://aka.ms/tmtinputval#inbuilt-encode">https://aka.ms/tmtinputval#inbuilt-encode</a>PriorityHighSDLPhaseImplementation87952830-0247-4d6d-b43e-3e2f46f47ed0AutoGeneratedd37480d8-de0a-4967-b94c-81ace2b9f751TH24falsefalseTH3387952830-0247-4d6d-b43e-3e2f46f47ed0117f99b4-6aba-4de8-babb-3e686b4faea9d37480d8-de0a-4967-b94c-81ace2b9f7515391df34-17a6-4ed9-87af-59d10800f0ee117f99b4-6aba-4de8-babb-3e686b4faea927287952830-0247-4d6d-b43e-3e2f46f47ed0:117f99b4-6aba-4de8-babb-3e686b4faea9:d37480d8-de0a-4967-b94c-81ace2b9f7510001-01-01T00:00:00HighTitleAn attacker steals messages off the network and replays them in order to steal a user's sessionUserThreatCategoryTamperingUserThreatShortDescriptionTampering is the act of altering the bits. Tampering with a process involves changing bits in the running process. Similarly, Tampering with a data flow involves changing bits on the wire or between two running processesUserThreatDescriptionAn attacker steals messages off the network and replays them in order to steal a user's sessionInteractionStringPOST Manually Process Call-IdPriorityHighSDLPhaseImplementation87952830-0247-4d6d-b43e-3e2f46f47ed0AutoGeneratedd37480d8-de0a-4967-b94c-81ace2b9f751TH33falsefalseTH9687952830-0247-4d6d-b43e-3e2f46f47ed0117f99b4-6aba-4de8-babb-3e686b4faea9d37480d8-de0a-4967-b94c-81ace2b9f7515391df34-17a6-4ed9-87af-59d10800f0ee117f99b4-6aba-4de8-babb-3e686b4faea927387952830-0247-4d6d-b43e-3e2f46f47ed0:117f99b4-6aba-4de8-babb-3e686b4faea9:d37480d8-de0a-4967-b94c-81ace2b9f7510001-01-01T00:00:00HighTitleAn adversary can gain access to sensitive data by performing SQL injection through Web AppUserThreatCategoryTamperingUserThreatShortDescriptionTampering is the act of altering the bits. Tampering with a process involves changing bits in the running process. Similarly, Tampering with a data flow involves changing bits on the wire or between two running processesUserThreatDescriptionSQL injection is an attack in which malicious code is inserted into strings that are later passed to an instance of SQL Server for parsing and execution. The primary form of SQL injection consists of direct insertion of code into user-input variables that are concatenated with SQL commands and executed. A less direct attack injects malicious code into strings that are destined for storage in a table or as metadata. When the stored strings are subsequently concatenated into a dynamic SQL command, the malicious code is executed. InteractionStringPOST Manually Process Call-IdPossibleMitigationsEnsure that type-safe parameters are used in Web Application for data access. Refer: <a href="https://aka.ms/tmtinputval#typesafe">https://aka.ms/tmtinputval#typesafe</a>PriorityHighSDLPhaseImplementation87952830-0247-4d6d-b43e-3e2f46f47ed0AutoGeneratedd37480d8-de0a-4967-b94c-81ace2b9f751TH96falsefalseTH9887952830-0247-4d6d-b43e-3e2f46f47ed0117f99b4-6aba-4de8-babb-3e686b4faea9d37480d8-de0a-4967-b94c-81ace2b9f7515391df34-17a6-4ed9-87af-59d10800f0ee117f99b4-6aba-4de8-babb-3e686b4faea927487952830-0247-4d6d-b43e-3e2f46f47ed0:117f99b4-6aba-4de8-babb-3e686b4faea9:d37480d8-de0a-4967-b94c-81ace2b9f7510001-01-01T00:00:00HighTitleAn adversary can gain access to sensitive data stored in Web App's config filesUserThreatCategoryTamperingUserThreatShortDescriptionTampering is the act of altering the bits. Tampering with a process involves changing bits in the running process. Similarly, Tampering with a data flow involves changing bits on the wire or between two running processesUserThreatDescriptionAn adversary can gain access to the config files. and if sensitive data is stored in it, it would be compromised.InteractionStringPOST Manually Process Call-IdPossibleMitigationsEncrypt sections of Web App's configuration files that contain sensitive data. Refer: <a href="https://aka.ms/tmtdata#encrypt-data">https://aka.ms/tmtdata#encrypt-data</a>PriorityHighSDLPhaseImplementation87952830-0247-4d6d-b43e-3e2f46f47ed0AutoGeneratedd37480d8-de0a-4967-b94c-81ace2b9f751TH98falsefalsetrue4.3falsefalseSelectYesNoShow Boundary ThreatsVirtualDynamic23e2b6f4-fcd8-4e76-a04a-c9ff9aff4f59ListA unidirectional representation of the flow of data between elementsfalseGE.DFBefore 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Generic Data FlowROOTLinefalseAnyAnyfalseA representation of a data storefalseGE.DSLower right of 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gA3tbmHb8dUAgCASQDc1OYevh1TCQAAJgFwU5t7+HZMJQAAmATATW3u4dsxlQAAYBIAN7W5h2/HVAIAgEkA3NTmHr4dUwkAACYBcFObe/h2TCUAAJgEwE1t7uHbMZUAAGASADe1uYdvx1QCAIBJANzU5h6+HVMJAAAmAXBTm3v4dkwlAACYBMBNbe7h2zGVAABgEgA3tbmHb8dUAgCASQDc1OYevh1TCQAAJgFwU5t7+HZMJQAAmATATW3u4dsxlQAAYBIAN7W5h2/HVAkBUBsAyPG3X3779nnev9lPEAAPqD90bQaAFALgAQIAgDQC4AECAIA0AuABAgCANALgAQIAgDQC4AECAIA0AuABAgCANALgAQIAgDQC4AECAIA0AuABAgCANALgAQIAgDQC4AECAIA0AuABAgCANALgAQIAgDQC4AECAIA0AuABAgCANALgAQIAgDQC4AECAIA0AuABAgCANALgAQIAgDQC4AECAIA0AuABAgCANALgAQIAgDQC4AECAIA0AuABAgCANALgAQIAgDQC4AECAIA0AuABAgCANALgAQIAgDQC4AECAIA0AuABAgCANALgAQIAgDQC4AECAIA0AuABAgCANALgAQIAgDQC4AECAIA0AuABAgCANALgAQIAgDQC4AECAIA0AuABAgCANALgAQIAgDQC4AECAIA0AuABAgCANALgAQkBsO0C4Pfz85dfvn2e92/2EwTAAwQAAJMAuKnNPXw7phIAAEwC4KY29/DtmEoAADAJgJva3MO3YyoBAMAkAG5qcw/fjqkEAACTALipzT18O6YSAABMAuCmNvfw7ZhKAAAwCYCb2tzDt2MqAQDAJABuanMP346pBAAAkwC4qc09fDumEgAATALgpjb38O2YSgAAMAmAm9rcw7djKgEAwCQAbmpzD9+OqQQAAJMAuKnNPXw7phIAAEwC4KY29/DtmEoAADAJgJva3MO3YyoBAMAkAG5qcw/fjqkEAACTALipzT18O6YSAABMAuCmNvfw7ZhKAAAwCYCb2tzDt2MqAQDAJABuanMP346pBAAAkwC4qc09fDumEgAATALgpjb38O2YSgAAMAmAm9rcw7djKgEAwCQAbmpzD9+OqQQAAJMAuKnNPXw7phIAAEwC4KY29/DtmEoAADAJgJva3MO3YyoBAMAkAG5qcw/fjqkEAACTALipzT18O6YSAABMAuCmNvfw7ZhKAAAwCYCb2tzDt2MqAQDAJABuanMP346pBAAAkwC4qc09fDumEgAATALgpjb38O2YSgAAMAmAm9rcw7djKgEAwCQAbmpzD9+OqQQAAJMAuKnNPXw7phIAAEwC4KY29/DtmEoAADAJgJva3MO3YyoBAMAkAG5qcw/fjqkEAACTALipzT18O6YSAABMAuCmNvfw7ZhKAAAwCYCb2tzDt2MqAQDAJABuanMP346pBAAAkwC4qc09fDumEgAATALgpjb38O2YSgAAMAmAm9rcw7djKgEAwCQAbmpzD9+OqQQAAJMAuKnNPXw7phIAAEwC4KY29/DtmEoAADAJgJva3MO3YyoBAMAkAG5qcw/fjqkEAACTALipzT18O6YSAABMAuCmNvfw7ZhKAAAwCYCb2tzDt2MqAQDAJABuanMP346pBAAAkwC4qc09fDumEgAATALgpjb38O2YSgAAMAmAm9rcw7djKgEAwCQAbmpzD9+OqQQAAJMAuKnNPXw7phIAAEwC4KY29/DtmEoAADAJgJva3MO3YyoBAMAkAG5qcw/fjqkEAACTALipzT18O6YSAABMAuCmNvfw7ZhKAAAwCYCb2tzDt2MqAQDAJABuanMP346pBAAAkwC4qc09fDumEgAATALgpjb38O2YSgAAMAmAm9rcw7djKgEAwCQAbmpzD9+OqQQAAJMAuKnNPXw7phIAAEwC4KY29/DtmEoAADAJgJva3MO3YyoBAMAkAG5qcw/fjqkEAACTALipzT18O6YSAABMAuCmNvfw7ZhKAAAwCYCb2tzDt2MqAQDAJABuanMP346pBAAAkwC4qc09fDumEgAATALgpjb38O2YSgAAMAmAm9rcw7djKgEAwCQAbmpzD9+OqQQAAJMAuKnNPXw7pkoIgO++/+ErADn+56+/fvs879/sJwiAByQEAAD8IwHwAAEAQBoB8AABAEAaAfAAAQBAGgHwAAEAQBoB8AABAEAaAfAAAQBAGgHwAAEAQBoB8AABAEAaAfAAAQBAGgHwAAEAQBoB8AABAEAaAfAAAQBAGgHwAAEAQBoB8AABAEAaAfAAAQBAGgHwAAEAQBoB8AABAEAaAfAAAQBAGgHwAAEAQBoB8AABAEAaAfAAAQBAGgHwAAEAQBoB8AABAEAaAfAAAQBAGgHwAAEAQBoB8AABAEAaAfAAAQBAGgHwAAEAQBoB8AABAEAaAfAAAQBAGgHwAAEAQBoB8IB//tc/f/3u+x8AIMa//Nt/rf+zUv0hAwAA+P8RAADwgQQAAHwgAQAAH0gAAMAHEgAA8IEEAAB8IAEAAB9IAADABxIAAPCBBAAAfCABAAAfSAAAwAcSAADwgQQAAHwgAQAAH0gAAMAHEgAA8IEEAAB8IAEAAB9IAADABxIAAPCBBAAAfCABAAAfSAAAwAcSAADwgQQAAHwgAQAAH0gAAMAHEgAA8IEEAAB8IAEAAB9IAADABxIAAPCBBAAAfCABAAAfSAAAwAcSAADwgQQAAHwgAQAAH0gAAMAHEgAA8IH+HgDfff/DVwDgM/w9AACAz7I+AgDvtj4CAO+2PgIA77Y+AgDvtj4CAO+2PgIA77Y+AgDvtj4CAO+2PgIA77Y+AgDvtj4CAO+2PgIA77Y+AgDvtj4CAO+2PgIA77Y+AgDvtj4CAO+2PgIA77Y+AgDvtj4CAO+2PgIA77Y+AgDvtj4CAO+2PgIA77Y+AgDvtj4CAO+2PgIA77Y+AgDvtj4CAO+2PgIA77Y+AgDvtj4CAO+2PgIA77Y+AgDvtj4CAO+2PgIA77Y+AgDvtj4CAO+2PgIA77Y+AgDvtj4CAO+2PgIA77Y+AgBv9vVP/wvm8MX4W+CLKgAAAABJRU5ErkJggg==Generic Data StoreROOTParallelLinesfalseAnyAnyfalseA representation of an external interactorfalseGE.EILower right of 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Generic External InteractorROOTRectanglefalseAnyAnyfalseA representation of a generic processfalseGE.PCentered on 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Generic ProcessROOTEllipsefalseAnyAnyfalseA border representation of a trust boundaryfalseGE.TB.BBefore labeliVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAOxAAADsQBlSsOGwAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAABGSURBVDhPY/hPIWBQ9Ev6z2jqDccPnr0ESxArzoDMAeEDZy+DFRIrDjeAVDCcDIDyyQajgTioAhGEQekdHx+bGIUGeP8HAJ4fIfJijo6MAAAAAElFTkSuQmCCGeneric Trust Border BoundaryROOTBorderBoundaryfalseAnyAnyfalseAn arc representation of a trust boundaryfalseGE.TB.LBefore labeliVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAZdEVYdFNvZnR3YXJlAEFkb2JlIEltYWdlUmVhZHlxyWU8AAABX0lEQVQ4T2NgNPXGh/mhGJscGCNzQArtgVgfxmcy87kAwlA5ZLVwDGOAFQPp/1Dcj8zHZwiY4LUPdgLSMM0YmM8+5JaAY5gRkI3dAJuUUlsgjVUzCM/ZuDPg////vEA2dgNAkqpBKTuBbKwGRNV0iQNpmCZQGMG9AxPk57IJvA6ksRrAYu67EEjLA7E+s7nPReQwAWtGC0CiMMwQkPNZ5H0TtqArIIRBAWueUCgM9gLQEG1QGHDbBr1YuftQDJDvapFYtAhdEwwDY+TO8cvXXUCWw8IAbMjCrXtDgDQHlK8E04CO1YPTVoA0A9nwQIQZAtYMxaBAw2oAFINSLaoBSFgfGEgPgDQ2jWAs5hZVCaSxGwB0Ca+iX9I2IBusGORn3YistTA+q4Xf59KJcy1BarEaAMJAQ8ABixRg6omN/fWgwF26Y38EzLsghfiwNhBbADELlC8KxEpAzAHh/2cAANCSU7ngF2KpAAAAAElFTkSuQmCCGeneric Trust Line BoundaryROOTLineBoundaryfalseAnyAnyfalseA representation of an annotationfalseGE.ACentered on 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Free Text AnnotationROOTAnnotationfalseAnyAnyMicrosoft C+AI Security11111111-1111-1111-1111-111111111111Azure Threat Model Template1.0.0.33falseRepresents a request from a source to a target.falseSE.DF.TMCore.RequestBefore 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RequestGE.DFLinefalseAnyAnyfalseRepresents a response from a target to a sourcefalseSE.DF.TMCore.ResponseBefore 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ResponseGE.DFLinefalseAnyAnyfalsefalseSelectSQLMongoDBAzure TableCassandraAPI TypeVirtualDynamicd456e645-5642-41ad-857f-951af1a3d968ListfalseSelectAllow access from all networksAllow access from selected networks (including Azure)Allow access from selected networks (excluding Azure)Azure Cosmos DB Firewall SettingsVirtualDynamicb646c6da-6894-432a-8925-646ae6d1d0eaListGlobally distributed, multi-model database service with support for NoSQLfalseSE.P.TMCore.AzureDocumentDBLower right of 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 Cosmos DBGE.DSParallelLinesfalseAnyAnyfalsefalseSelectAllow access from all networksAllow access from selected networksAzure Key Vault Firewall SettingsVirtualDynamiccd610fb8-4fbd-49c0-966f-8b4634b39262ListfalseSelectTrueFalseAzure Key Vault Audit Logging EnabledVirtualDynamic78bf9482-5267-41c6-84fd-bac2fb6ca0b9ListfalseSelectManaged IdentitiesService or User Principal and CertificateService or User Principal and SecretAuthenticating to Key VaultVirtualDynamicae94fa17-596d-476e-a283-0afc166dcf26ListTool for securely storing and accessing secretsfalseSE.DS.TMCore.AzureKeyVaultLower right of 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Azure Key VaultGE.DSParallelLinesfalseAnyAnyfalsefalseSelectTrueFalseAzure Redis Cache TLS EnforcedVirtualDynamic866e2e37-a089-45bc-9576-20fc95304b82ListfalseSelectAllow access from all networksAllow access from selected networksAzure Redis Cache Firewall SettingsVirtualDynamic1bda806d-f9b6-4d4e-ab89-bf649f2c2ca5ListAzure Redis CachefalseSE.P.TMCore.AzureRedisLower right of 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Azure Redis CacheGE.DSParallelLinesfalseAnyAnyfalsefalseSelectFileTableQueueBlobStorage TypeVirtualDynamicb3ece90f-c578-4a48-b4d4-89d97614e0d2ListfalseSelectTrueFalseHTTPS EnforcedVirtualDynamic229f2e53-bc3f-476c-8ac9-57da37efd00fListfalseSelectAllow access from all networksAllow access from selective networksNetwork SecurityVirtualDynamiceb012c7c-9201-40d2-989f-2aad423895a5ListfalseSelectTrueFalseCORS EnabledVirtualDynamicc63455d0-ad77-4b08-aa02-9f8026bb056fListAzure StoragefalseSE.DS.TMCore.AzureStorageLower right of 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Azure StorageGE.DSParallelLinesfalseAnyAnyfalsefalseSelectAzure-RedisGenericCache TechnologiesVirtualDynamic2226af6a-5cfe-4283-a62d-f35d3234336dListfalseSelectAllCache VersionVirtualDynamic250ddabe-ef50-4fe3-9f7d-74881a8c608eListCachefalseSE.DS.TMCore.CacheLower right of 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.DSParallelLinesfalseAnyAnyfalsefalseSelectGenericOnPremDatabase TechnologiesVirtualDynamic6047e74b-a4e1-4e5b-873e-3f7d8658d6b3ListfalseSelectAllV12MsSQL2016MsSQL2012MsSQL2014SQL VersionVirtualDynamic0a5c9e0f-f68c-4607-9a1a-a02841f1e9deListfalseSelectYesNoSSIS packages UsedVirtualDynamic649208cc-3b55-40ff-94b9-015c0fb0c9e8ListDatabasefalseSE.DS.TMCore.SQLLower right of stenciliVBORw0KGgoAAAANSUhEUgAAAgAAAAIACAYAAAD0eNT6AAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAABcRgAAXEYBFJRDQQAAHCZJREFUeF7t3S2UVEcaBuDIlSsjVkSsWBGxIiJiRcQKZCwyErEiIiIiErEiIgKBQCAwiBErECsQESNWICIQCAQCEREREREzO99wOgzNC8xPz3T3fR/xmDonJ8z9ble9t25V3Y+Ojo4AgDKxEdiu337//ejx4Ys/PHr8/Oi7fx9+0Ff/+u/RF18+vBLf3s7/z9Pu3P/pjX/38xe/Hv85+W8Etis2Apf39NkvfwyEDw6evTFQfv3dj28Mrn//54Ojjz7+fvH+9o/7b/zdcx1OX5cJOqtrNtdv/ZoCmxMbgXf75dfXT+e3f/jfycB165vHfwxqaeDj4v70lx/+uLarWYgJVHP9nzz9+bgkuU7A+8VGaLUa3O89fPrHU+lq8Pn407txgGI3rOq0mlWYGgoJ8G6xEZZuBoaDR6/eq9+89ehk4EiDCsuxev1wOhzMWov1ewNaxEZYgtU7+OnwV+/cPcWz7s9/vXNyb8xrnHmlM/eMxYs0iI2wT6azXj3NT0fesqCOq/f5jYdHX371n5N7a+4xCxNZktgIu2re58707SwGm8F+FoiljhuuympR4tyDsxhRKGBfxUbYBTMV+/3dJydTs/Mkljpj2AVCAfsoNsJ1W72rnwV5s1grdbKwT4QCdl1shKu2GvCng0ydJyzRLDicNQUzs2V7ItsWG2GTZqvVnPC2em+fOkZoJBCwTbERLmMO01kN+N7dw9mdDgReGXDVYiOc12yRmr32tuDB5sy5FbMuZj6yJBCwabERPuTlz7+ddErztGIrHlyPCQTzxccJ3E4x5LJiIySHT16eTOt7yoftm+A9AXzOxZhAvv57hQ+JjTDmXf5sX5onDkfowm6b9TZzlLFXBZxVbKTXdB6zAOnGzYPYyQC775PP7p2syZnttuu/cViJjXSZ6cMZ9B3AA8szOwtmFm9m86wb4LTYyPLN9P68O7QvH3qswsCs51nvE+gTG1muWT0824qs3Idu85pg1gz49HGv2MiyzAlj80EdC/mAZNb8zIygVwRdYiP7b1L9nLU/KT/94AHWeUXQJTayv2aK3wp+4LK8Ili+2Mh+mQV9cyqfp33gKsyBQ7YULk9sZD9MMp93+zNtl360AJs0p4DOWoH1voj9FBvZbfOlvUnk6QcKcNVmQfG8HpjZx/X+if0RG9k9szp3krfDeliZVz5zjsNZzeKuWRj6Iem/fR9bSntN7WcW0jqB/RQb2R2TsKdTNs2/LBPkVgPozOacHoAn6M371tP2rYOd0yXX/4YxT42rv3P+7tU1sEV1/1knsH9iI9s3T/zTSRr498M8Ca0GszmDfWo3xyufHvzssT6bCTurazbH164Cw+xumetrsetum3UCsxtpva7sntjI9swgMQOHJ6LdMSFsBp4ZgFaD0XRwM0CZ+tyemR1bBYXVzMK85phaeVW2fRMEpjbrdWN3xEa2Y6Z+Pd1szwwcq+n4efLUee2/+brlKiB8e/vV+ga/ses113xOI12vDdsXG7le8zTpieV6zMzKdEgzyM/ZCTM4zPvq9ZqwfDMoTf3nXpiFbHNfpHuGzZhwbcZst8RGrsds55tpsvRj4fKmQ5+OfZ7+pqO3ZYmzmFmD+W1OMJhBSzjfrFkjI3TvhtjI1ZoOxtPG5sxT/er9/MymzPVdv+ZwWRMiZ9ZoBrDPb/j9XsYsmp3fq1C+XbGRqzEL/OY9ZPpBcHbT+U4nPO/pTSmyTav1BTNTYOHu+c0C21n0vH5duR6xkc2bKUWLj85vOtXpXFfT+OvXFXbJBNIJpmYJzmdes/gC4fWLjWzOvOuaASzd9Lxtpgbnes1Uq6l89t3M+s1rqVmLYi3Bh802Tq8Frk9sZDNmW5+DfD5snpTm1YgnAJZuZggm3N689Ujf8A5zXXxw6HrERi5nnvp9k//d5lXIPBHNVKm0T7MJvfN6y26gt00farfA1YqNXJyn/mwG/Xkv6kAQyGZ2YBbECQOvmQ24WrGR85t3ffP+Kt3ErQz6cDHCwJvmlYnZws2LjZzPLFbzQ31lVu0b9GFzVmGgfRHh9C3WCW1WbOTs5j22Kf9X7+vmWqxfH2BzZgCcmcbZLZN+hw2cG7A5sZGzmcU76QZtMYl8Vu/PE8r6tQGuzkyHz26C1lmB2SrslcDlxUber/19v6d92B2tswITfpwVcjmxkXeb1Nl6jv90Mp72YTdN3zTn6ze9kpy/1QmhFxcbyWbwa5xyM/DD/mgLAjPzYavgxcRG3jYDYNtZ/gZ+2F9tQWDWI61fA94vNvKmtsF/3vEb+GEZJgi0fIV0HlrW/37eLTbyWtPgP6v656uF69cA2H9zNkfDFwqFgLOLjbwy51C3DP5zeM88KaxfA2BZZh/90l8LCAFnExt5tdWv4XS/+RudrgVdGj5TPh8cW/+7eVNsbDeDf8PX/Oapf/1vB3rMYUKpb1iKOaxt/W/mtdjYbgbGdDMtxWybmR/++t8N9Jl99Et+JeDQsneLjc0OHj2PN9FS+KAGsG5O1FvqGSfzwOOwoCw2tpr3YktOwrMCeP7G9b8bYBYBL/WU03nw0fe9LTa2WvIRv5PurfIH3mfJi59n0eP639suNjaaoyTTTbMEk34d7AOcxZK3P/uU8JtiY5u54WeQTDfMvpv3X975A+cxhwYt8XXo9Ifzt63/va1iY5s5NCLdLEswixrX/16AD5lTQVOfsu9mLdT639oqNjaZNJhukiXwzgu4jKUeFuTrga/ExiZLPg3LVBdwGUt9QLIr4JXY2GJugHknlG6QfefpH9iEpR6M5iTU8gCw5BP/PP0Dm7DUB6X5m2bb4/rf2yQ2NpjCL/XQn9nHu/73AlzUUj8j3L4tMDY2WOoK13Hz1qPjPzH/3QDntdSdUrMWoHkWIDY2WPLWP1/AAjZp+pTU1yzBPAyu/70tYmODpS7+G/b+A5u05I+kzcPg+t/bIjYu3ZL3/g9fvgI2afqU1NcswawFa30NEBuXbsnn/g/f+gc2afqU1NcsRetDU2xcuiVv/xv2twKbtPQ+s3XdVGxcuiV/9nc4BAjYpCWfmDpa+8zYuHRLDwDzKc/1vxngopb6eeCV1j4zNi7d0m/mYScAsAlL3gFw2vrf3SA2Lt1Sv/1/mtMAgU2YviT1MUvTuBMgNi5dKv4SmQUALqPl6X88f/Hr8Z+cr8NSxcalS8Vfoknu7R+7AC5m+o6Wp/8hAJRIxV8q3wUALmL6jtSnLJUAUCIVf8m++/fh8Z+drwXAuukzUl+yZAJAiVT8pXtw8Oz4T8/XA2Bl+orUhyydAFAiFX/p5uNHzV+9Aj5s+oglfyjtfQSAEqn4DeaHPd9BWL8eAPPk3zr4DwGgRCp+E98KAE779nbfO/91AkCJVPw2c/b1L7/aIgjNZqvf0s/5PysBoEQqfqO//eP+0dNnvxxfknydgOWa337TPv8PEQBKpOK3mnd+M/3nwCDoML/1+fxt8/v+RAAokYrfbj6QZJcALNvhk5cnM3+pD2gnAJRIxeeVeR/48uffji9TvnbA/pn1Pl/967/xN88rAkCJVHxe+/Nf75ycHmiRIOy3me7//u6To4YvoF6WAFAiFZ+3CQKwnwz85ycAlEjF590EAdgPBv6LEwBKpOLzYasgYI0A7JYJ5wb+yxEASqTicz7zqVC7BmC7ZlX/LO6zpe/yBIASqfhczGwfnD3FZgXgeszT/p37P9nOt2ECQIlUfC5nnkDmSWSeSNavN3B5c3LfrW8ee9q/IgJAiVR8NmdmBeaDQ0+e/nx8uXMNgA+bQX/W3Xjav3oCQIlUfK6GMADnY9DfDgGgRCo+V08YgMygv30CQIlUfK7XbFeaNQP3Hj61gJA6s5Dv4NHzk3f6E4zTb4TrJQCUSMVnu+azpDM7YGshSzULZOcp//MbD+NvgO0SAEqk4rNbbtw8ODnYxK4C9tW86prtevOBrTlEK93n7A4BoEQqPrvtiy8fHn17+/Bk2tQrA3bNTOnP7NU84c+9aqve/hEASqTis1/mvemcRmiWgG1YPd3POhYL95ZBACiRis/+m3er0yHPyYSPD1/4eBEbMffSDPazRsXT/XIJACVS8Vmm2W0wnfZMzc7rg9lutX4/wJhXSzPYz70ys0uzMDXdUyyTAFAiFZ8uEwpmcdZ09rMV0YxBj3lltHpfP9vw5l6wSA8BoEQqPoyZ3p0BYZ4AZ4B4cPDsJBzMd9bX7yN2VxrkfSqX9xEASqTiw1nM4sPTswdjBpoJCY0dyHWbIDbXeswC0Ln+s+5jamJ/PZchAJRIxYdNmenkGZBOzySM1eLEFa8cXpmn9dU1mdcxq+u1WnQ3rLTnqgkAJVLxYZtWixVXTs8wrMwT7+kAMbb5XYXVornT5pXJ+r97NQW/4kmdXSQAlEjFB6CXAFAiFR+AXgJAiVR8AHoJACVS8QHoJQCUSMUHoJcAUCIVH4BeAkCJVHwAegkAJVLxAeglAJRIxQeglwBQIhUfgF4CQIlUfAB6CQAlUvEB6CUAlEjFB6CXAFAiFR+AXgJAiVR8AHoJACVS8QHoJQCUSMUHoJcAUCIVH4BeAkCJVHwAegkAJVLxAeglAJRIxQeglwBQIhUfgF4CQIlUfAB6CQAlUvEB6CUAlEjFB6CXAFAiFR+AXgJAiVR8AHoJACVS8QHoJQCUSMUHoJcAUCIVH4BeAkCJVHwAegkAJVLxAeglAJRIxQeglwBQIhUfgF4CQIlUfAB6CQAlUvEB6CUAlEjFB6CXAFAiFR+AXgJAiVR8AHoJACVS8QHoJQCUSMUHoJcAUCIVH4BeAkCJVHwAegkAJVLxAeglAJRIxQeglwBQIhUfgF4CQIlUfAB6CQAlUvEB6CUAlEjFB6CXAFAiFR+AXgJAiVR8AHoJACVS8QHoJQCUSMUHoJcAUCIVH4BeAkCJVHwAegkAJVLxAeglAJRIxQeglwBQIhUfgF4CQIlUfAB6CQAlUvEB6CUAlEjFB6CXAFAiFR+AXgJAiVR8AHoJACVS8QHoJQCUSMUHoJcAUCIVH4BeAkCJVHwAegkAJVLxAeglAJRIxQeglwBQIhUfgF4CQIlUfAB6CQAlUvEB6CUAlEjFB6CXAFAiFR+AXgJAiVR8AHoJACVS8QHoJQCUSMUHoJcAUCIVH4BeAkCJVHwAegkAJVLxAeglAJRIxQeglwBQIhUfgF4CQIlUfAB6CQAlUvEB6CUAlEjFB6CXAFAiFR+AXgJAiVR8AHoJACVS8QHoJQCUSMUHoJcAUCIVH4BeAkCJVHwAegkAJVLxAeglAJRIxQeglwBQIhUfgF4CQIlUfAB6CQAlUvEB6CUAlEjFB6CXAFAiFR+AXgJAiVR8AHoJACVS8QHoJQCUSMUHoJcAUCIVH4BeAkCJVHwAegkAJVLxAeglAJRIxQeglwBQIhUfgF4CQIlUfAB6CQAlUvEB6CUAlEjFB6CXAFAiFR+AXgJAiVR8AHoJACVS8QHoJQCUSMUHoJcAUCIVH4BeAkCJVHwAegkAJVLxAeglAJRIxQeglwBQIhUfgF4CQIlUfAB6CQAlUvEB6CUAlEjFB6CXAFAiFR+AXgJAiVR8AHoJACVS8QHoJQCUSMUHoJcAUCIVH4BeAkCJVHwAegkAJVLxAeglAJRIxQeglwBQIhUfgF4CQIlUfAB6CQAlUvEB6CUAlEjFB6CXAFAiFR+AXgJAiVR8AHoJACVS8QHoJQCUSMUHoJcAUCIVH4BeAkCJVHwAegkAJVLxAeglAJRIxQeglwBQIhUfgF4CQIlUfAB6CQAlUvEB6CUAlEjFB6CXAFAiFR+AXgJAiVR8AHoJACVS8QHoJQCUSMUHoJcAUCIVH4BeAkCJVHwAegkAJVLxAeglAJRIxQeglwBQIhUfgF4CQIlUfAB6CQAlUvEB6CUAlEjFB6CXAFAiFR+AXgJAiVR8AHoJACVS8QHoJQCUSMUHoJcAUCIVH4BeAkCJVHwAegkAJVLxAeglAJRIxQeglwBQIhUfgF4CQIlUfAB6CQAlUvEB6CUAlEjFB6CXAFAiFR+AXgJAiVR8AHoJACVS8QHoJQCUSMUHoJcAUCIVH4BeAkCJVHwAegkAJVLxAeglAJRIxQeglwBQIhUfgF4CQIlUfAB6CQAlUvEB6CUAlEjFB6CXAFAiFR+AXgJAiVR8AHoJACVS8QHoJQCUSMUHoJcAUCIVH4BeAkCJVHwAegkAJVLxAeglAJRIxQeglwBQIhUfgF4CQIlUfAB6CQAlUvEB6CUAlEjFB6CXAFAiFR+AXgJAiVR8AHoJACVS8QHoJQCUSMUHoJcAUCIVH4BeAkCJVHwAegkAJVLxAeglAJRIxQeglwBQIhUfgF4CQIlUfAB6CQAlUvEB6CUAlEjFB6CXAFAiFR+AXgJAiVR8AHoJACVS8QHoJQCUSMUHoJcAUCIVH4BeAkCJVHwAegkAJVLxAeglAJRIxQeglwBQIhUfgF4CQIlUfAB6CQAlUvEB6CUAlEjFB6CXAFAiFR+AXgJAiVR8AHoJACVS8QHoJQCUSMUHoJcAUCIVH4BeAkCJVHwAegkAJVLxAeglAJRIxQeglwBQIhUfgF4CQIlUfAB6CQAlUvEB6CUAlEjFB6CXAFAiFR+AXgJAiVR8AHoJACVS8QHoJQCUSMUHoJcAUCIVH4BeAkCJVHwAegkAJVLxAeglAJRIxQeglwBQIhUfgF4CQIlUfAB6CQAlUvEB6CUAlEjFB6CXAFAiFR+AXgJAiVR8AHoJACVS8QHoJQCUSMUHoJcAUCIVH4BeAkCJVHwAegkAJVLxAeglAJRIxQeglwBQIhUfgF4CQIlUfAB6CQAlUvEB6CUAlEjFB6CXAFAiFR+AXgJAiVR8AHoJACVS8QHoJQCUSMUHoJcAUCIVH4BeAkCJVHwAegkAJVLxAeglAJRIxQeglwBQIhUfgF4CQIlUfAB6CQAlUvEB6CUAlEjFB6CXAFAiFR+AXgJAiVR8AHoJACVS8QHoJQCUSMUHoJcAUCIVH4BeAkCJVHwAegkAJVLxAeglAJRIxQeglwBQIhUfgF4CQIlUfAB6CQAlUvEB6CUAlEjFB6CXAFAiFR+AXgJAiVR8AHoJACVS8QHoJQCUSMUHoJcAUCIVH4BeA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DatabaseGE.DSParallelLinesfalseAnyAnyfalsefalseSelectYesNoAzure SQL DB SSIS Packages UsedVirtualDynamicd8830a8d-37b8-472e-abcc-0d157857f576ListfalseSelectAllow access from all networksAllow access from AzureAllow access from selected networksAzure SQL DB Firewall SettingsVirtualDynamice68e212d-896e-403e-8a2d-8c6d2b2505dfListfalseSelectTrueFalseAzure SQL DB TDE EnabledVirtualDynamic3a2a095f-94bc-467f-987c-8dac8307cdc6ListfalseSelectTrueFalseAzure SQL DB Auditing EnabledVirtualDynamic6a3509e5-a3fd-41db-8dea-6fb44b031e4bListfalseSelectTrueFalseVulnerability Assessment EnabledVirtualDynamic212cf67e-047a-4617-860f-92282e04b8d8ListServer based TDS service for highly available, globally distributed appsfalseSE.DS.TMCore.AzureSQLDBLower right of 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 SQL DatabaseGE.DSParallelLinesfalseAnyAnyfalsefalseSelectAllow access from all networksAllow access from selected networks (including Azure)Allow access from selected networks (excluding Azure)Azure SQL DW DB Firewall SettingsVirtualDynamicb8c8850c-979b-4db0-b536-9aa364b7e6a2ListfalseSelectTrueFalseAzure SQL DW DB TDE EnabledVirtualDynamicd2ce181d-abae-448d-8ef4-9acdbeb839feListfalseSelectTrueFalseAzure SQL DW DB Auditing EnabledVirtualDynamiccd2a18a2-cebd-4b0f-ae4c-964b190e84f2ListCloud-based Enterprise Data WarehousefalseSE.DS.TMCore.AzureSQLDWDBLower right of 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Azure SQL Data Warehouse DatabaseGE.DSParallelLinesfalseAnyAnyfalsefalseSelectAllow access from all networksAllow access from AzureAllow access from selected networksAzure MySQL DB Firewall SettingsVirtualDynamic9afccb81-bc8b-4527-ad05-f90ec3e396cbListfalseSelectTrueFalseAzure MySQL DB TLS EnforcedVirtualDynamic4d3b2548-8c31-460e-88e5-4c26135003acListFully managed, enterprise-ready community MySQL database as a service for app development and deploymentfalseSE.DS.TMCore.AzureMySQLDBLower right of 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Azure Database for MySQLGE.DSParallelLinesfalseAnyAnyfalsefalseSelectAllow access from all networksAllow access from AzureAllow access from selected networksAzure Postgres DB Firewall SettingsVirtualDynamicba682010-cfcf-4916-9f88-524f8d9ce8a8ListfalseSelectTrueFalseAzure Postgres DB TLS EnforcedVirtualDynamic65a8827c-6efd-4243-aa81-0625c4aea98eListFully managed, enterprise-ready community PostgreSQL database as a service for app development and deploymentfalseSE.DS.TMCore.AzurePostgresDBLower right of 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SsGYFsa/ocTAAQAAeBCf3787FUmGo3HFVhGZvVnpU528qyuSU4jAAgAAsCVZKbx59+8MDwAC8m96pOnz9/0wFXXIOcRAAQAAeDKsnIgLxrKpiPjsQbOl217s0lXdb3xcAKAACAALCi9Anli8a4BOE+25k6Q9rS/HAFAABAAViIMwIdp9NclAAgAAsAGhAF4S6O/HQFAABAANpYbX1YSZFazZYXsXbbXzmRZY/rbEwAEAAFgMr//+9veAUsL2YOsiskkvjzl25N/LgKAACAATCwrCrLJSZ6YrCrgFmSNfhqWbJRlnf7cBAABQAC4IQkEeUthbq7pIcjN9vhvCWvLsFWe8NNrld6r6rxlTgKAACAA3LjDkEFuwuYQsLRMXP3i3y/ezFvRpX/bBAABQADYmUwqTC/Bp1+9DQVWGvAQh678DD99/OT5m3OqOt+4XQKAACAANJHx2EzEevT1izcXvi2LOcjM/CzHy9BSZud7su9BABAABIDGDr0FCQaHeQUmG+5TAl9u+Flumr91JpeapNebACAACACUfvPobTjI/II0GLlZuGHM7dDIH57mM06fv2Emj1Z/Y3pzPQsAAgAPksmHx70HGSs+hASrE64vEzxzbNNLk+Md6a7P30CXPQ8hAAgAAgCL+d3nb0NCZCLZoeFKN/QhLOT8G8/JLjLccjgOmZtxOD7pnj8cN1vkshQBQAAQAJjGYdjh2HFwODhMZPyQawaL44a6cuhyHx035AfV74Yt5Nwdz/VuysJOBACAfgQAAUAAAGhIABAABACAhgQAAUAAAGhIABAABACAhgQAAUAAAGhIABAABACAhgQAAUAAAGhIABAABACAhgQAAUAAAGhIABAABACAhgQAAUAAAGhIABAABACAhgQAAUAAAGhIABAABACAhgQAAUAAAGhIABAABACAhgQAAUAAAGhIABAABACAhgQAAUAAAGhIABAABACAhgQAAUAAAGhIABAABACAhgQAAUAAAGhIABAABACAhgQAAUAAAGhIABAABACAhgQAAUAAAGhIABAABACAhgQAAUAAAGhIABAABACAhgQAAUAAAGhIABAABACAhgQAAUAAAGhIABAABACAhgQAAUAAAGhIABAABACAhgQAAUAAAGhIABAABACAhgQAAUAAAGhIABAABACAhgQAAUAAAGhIABAABACAhgQAAUAAAGhIABAABACAhgQAAUAAAGhIABAABACAhgQAAUAAAGhIABAABACAhgQAAUAAAGhIABAABACAhgQAAUAAAGhIABAABACAhgQAAUAAAGhIABAABACAhgQAAUAAAGhIABAABACAhgQAAUAAAGhIABAABACAhgQAAUAAAGhIABAABACAhgQAAUAAAGhIABAABACAhgQAAUAAAGhIABAABACAhgQAAUAAAGhIABAABACAhgQAAUAAAGhIABAABACAhgQAAUAAAGhIABAABACAhgQAAUAAAGhIABAABACAhgQAAUAAAGhIABAABACAhgQAAUAAAGhIABAABACAhgQAAUAAAGhIABAABACAhgQAAUAAAGhIABAABACAhgQAAUAAAGhIABAABACAhgQAAUAAAGhIABAABACAhgQAAUAAAGhIABAABACAhgQAAUAAAGhIABAABACAhgQAAUAAAGhIABAABACAhgQAAUAAAGhIABAABACAhgQAAUAAAGhIABAABACAhgQAAUAAAGhIABAABACAhgQAAUAAAGhIABAABACAhgQAAUAAAGhIABAABACAhgQAAUAAAGhIABAABACAhgQAAUAAAGhIABAABACAhgQAAUAAAGhIABAABACAhgQAAUAAAGhIABAABICN/ObRD6/+8I+f/ufPj5+9+uyr5/f69LXjf/frv/5Qfj6/9H+fvTvm9x3v4+P8u89/LD8PbpkAIAAIAAtLQ/+nfz579ejrF4tecM9e/ufN53/x7xf/a7y6hoNDQ5+G/Mn3L6923HOtHI7xX/71TDDgpgkAAoAAcGW///uPbxrgNDw5tuPxXtuL19d4LvQEkASRvYaC/LbPv3nx6puf1r2p5fg+/eHlq0+ePn/127/dfiAYf9+aqvqwHAFAABAAriBP+Wn0v3++fYN/im+f/fymsUyjmafl6jfdgtT/y29fvkojfPz7tpRje8thYPw9a6rqw3IEAAFAAHigNJwZR87T33hMb8nPrzNLGtHqN84oDetsjf5dcoNNSKl+x6zG37Cmqj4sRwAQAASAM6ULPU/Pt9AAneoWzoEMrTz+7jbDVo7vx0+e30Rvy1j3NVX1YTkCgAAgAJwhE78y2W48hrdu5nPgoy9+2s2NKudOgkD1O2cx1nlNVX1YjgAgAAgAJ8hs7z1fLDOeA5lXka7+sa57kHkCWaVQ/e6tjXVdU1UfliMACAACwAekyzZLyTJOfnzM9ma2cyCT6PY0xHKXDGnMtipjrOOaqvqwHAFAABAA7pDJZrcyq/9Ss5wD6WnJ0/FYvz3LsECGOarjsYWxfmuq6sNyBAABQAAopPHPcRmP1V7NcA5kRUWHp/67ZBlpdVzWNtZrTVV9WI4AIAAIAINujX9seQ5kmCU764116iibR229UmCs05qq+rAcAUAAEACOdGz8Y6tzIOPf3br875OdDLecFzDWZ01VfViOACAACAD/1bXxjy3OAY3/3XJctgoBY13WVNWH5QgAAoAA8F9r7yE/k7XPAY3//fI3SSitjt+SxnqsqaoPyxEABAAB4LUsOxuPSydrngNZ36/xP01WoazdEzDWYU1VfViOACAAtA8Aecra+zr/+6x1DmSCm8b/POmZWnNi4Pj9a6rqw3IEAAGgfQBwEax3Dtz6i5O2ktUB1fFcwvjda6rqw3Lc+wSA1gEge/uPx6OjNc4BS/0u8+jrF+Vxvbbxe9dU1YflCAACQNsAkLHVzhvPHFv6HOg+x+Ja1nh/wPida6rqw3IEAAGgbQDw9P/OkudAtrntPsfiWrJt8NKTAsfvXFNVH5YjAAgAbQOA8eh3ljoHMnktnz1+Hw+39HyA8fvWVNWH5QgAAkDLAJClaONx6Gypc2Cvr/Pd2p/++aw83tcwfteaqvqwHAFAAGgZAD5+Mu+YdP4euTDzpJdXEY8+/+bFm/9+zTcVLnEOpJEav4fryFDAUksDx+9aU1UfliMACAAtA8Bsu/6lMc/b4NIzUdX3Q37/9x/fTLJLYEjDMH72Ka59DqRxemhdOM1Sbw8cv2dNVX1YjgAgALQLANn4ZzwGW0nDf+13weed+unhePzdy5NXOVz7HDDrf3mZWPmQwHif8XvWVNWH5QgAAkC7AJD3zo/HYAu5+Jae0Z0n8fze+yY8XvMcSKN0a7P+87c4GP/bzDIcVP0NLjF+x5qq+rAcAUAAaBcActMcj8HacszX3uM9DXO6jfPdVX2qf/MQs2/4kzCUUHRfz0vW3Kcnozpes1iiF2D8jjVV9WE5AoAA0C4AzLD8Lw1LVbe1/PHLn967+K91Dsz69J/5CNlJ76Fv10tgmPUdBtfeIXD8/DVV9WE5AoAA0C4AzPBEt8VrXiuZQJhAdK1zII3R+Fu3lgmf13pKnqH3aHTtFQHj56+pqg/LEQAEgHYBYIbtf6t6bSlBoCo/x4wz/9NgX3u5XHaQnK2X45o9SuNnr6mqD8sRAASAdgFg/P1buPa47Qxm21shDXVVz2uYbXvjrCap6vkQ42evqaoPyxEABAABYAMZg6/qdstmGiNfao38sdneJZHln1U9zzV+7pqq+rAcAUAAEAA2sOb73deQxmf8jVvJKoSqjkuYaavj7BJZ1fFc4+euqaoPyxEABAABYCNrPKWuJY3P+Pu2kBtaVb+lZH7BNbdkvkQmO1Z1PNf4uWuq6sNyBAABoF0AyO8dj8FWsrysquOtmaURvMZkxnPN9M6Da6wuGT9zTVV9WI4AIAC0CwCzNFaRiWRb7wlwqVm6/7ccVpll/sM1zqXxM9dU1YflCAACQLsAMONJn7X4Wzy9XsMs3f9bHr9ZegEyJ6Gq3znGz1xTVR+WIwAIAO0CwIybuRzkKfZas7nXMsNNJC8+quq2phl6lq6xHHD8zDVV9WE5AoAA0C4AzLZ8q5IgcAs9ApkEN8N6+DyBV/Vb0yw9IZe+Y2L8vDVV9WE5AoAA0C4AzPQ64PscXlxT/Y4ZJKSMdV5bAsi1d/t7iBmORVy6x8T4eWuq6sNyBAABoF0AiPzm8TjMLFvsZtngbDsIZtLZWNe1JSRVddvCDOfVpctLx89bU1UfliMACAAtA8Dsr6y9S552M9FrluGBjL2PdVzbTKsoZjivLp0IOH7emqr6sBwBQABoGQBm6a69RDZ+2Xp4YIaJbzNNmpxhNUBu6lXdTjV+3pqq+rAcAUAAaBkAYtb3u58rf78lX3zzIVtPAMz3V/XaSoZoxjqu7dKVAOPnramqD8sRAASAtgFgtrfXXWrtIDBDY5cQV9VtS1u/bvrSUDR+3pqq+rAcAUAAaBsAMnN865v1EtYKAnkl7vjda5th/f8oQzNjPdd2yWTR8bPWVNWH5QgAAkDbABB76wU4loZoyfHxGca7Z3yh0gwTARPOqrqdYvysNVX1YTkCgADQOgDEDE9sS0l38FKN5AxLALea+/AhOd5jPdf2h38IANxPABAA2geAPawIuM8SvQEz7Hw3ww6Aoxl2mhQAOIUAIAC0DwDx6Ovb3BfgHOkNuOYT8wzvVLikoVvKDAHgkuWh42etqaoPyxEABAAB4L+y//54bPYoYaf6/efKhjPjZ69txgCQrXjHeq7tkqA3ftaaqvqwHAFAABAA/iurArKt7Hh89iiz5y/dP3+GADDjmxMTSsZ6rk0A4BQCgAAgABzJm9T2skHQfXLxX/LmuBl6TPJip6puWxIAHq6qD8sRAAQAAWDQLQQ8tCdghpuHHoCaAMApBAABQAAopFGc4UU3a3joZjoz3DzMAahd8krg8bPWVNWH5QgAAoAA8AEzLHVbw0MmBs4QkC599/0SZlgFcEkwGj9rTVV9WI4AIAAIAPfIWvOtX3qzhuyKWP3+u8wwCfCSru6lzLC75CWvix4/a01VfViOACAACAAnyGSzva8QSMg5Zw95AaA2Q6/RJZMjx89aU1UfliMACAACwBnS5fzs5ZvugPJY3rrsY1/97soMDV3qUNVtSzNskHTJ6o7xs9ZU1YflCAACgABwpkwQ3PPOgad2H88QANLYVnXb0gxzI6p6nWr8rDVV9WE5AoAAIAA8ULpZ88S8t/kBWd9f/d7RDJPd8o6Dqm5byvU01nNNOR+rep1q/Lw1VfVhOQKAACAAXCjdrXkD3NY3/ms6pRdghvXulzZ215ZzYazj2i4NRePnramqD8sRAAQAAeCK8hKWPbxe+JRlgekBGf/dFi6Z8X5tWTEy1m9tlw6LjJ+3pqo+LEcAEAAEgAVkh7rciG91wuCp58T477Yw00qAGeZFXPImwBg/b01VfViOACAACAALyw35FpcQfvTF/ZvJzDDscc7KhaXN8He+dHvk8fPWVNWH5QgAAoAAsJJ0madX4FYmDZ4yDDDDC4HSy3Lpmw2vIXsobP23ffH6fl7V7RzjZ66pqg/LEQAEAAFgZWkoZthE5z6nnBefPN2+yzsu7fa+hkwEHeu1ttzQq7qdY/zMNVX1YTkCgAAgAGwkPQKzB4Gq3sdmWAkQ6Xqv6remGYZDHvJOh9H4mWuq6sNyBAABQADYWMbaZ50seN+Wsul6n2VI4766LmmGNwBGViFU9TvH+JlrqurDcgQAAUAAmECGBb59Nt/FeMoSu1nqveWugDPcSBPErjEXYvzcNVX1YTkCgAAgAEwiIWCGbuRjp7xud4albwdb7Akww9v/IsNJVf3ONX7umqr6sBwBQAAQACaSBmz8+2zplDX2WXY2/rutpDdizRUB+e2zDIGcEtZOMX7umqr6sBwBQABoGQAye33GV8nGDEvrDk59295MwxeZjV/VcQmz7PqY5X/XCj7jZ6+pqg/LEQAEgJYB4NBtnW7TS16duoRZupQjQamq42iGJXAHeSK/1tPwh8y0guNa3f8xfvaaqvqwHAFAAGgdACIz8GfqDZhlaV2celxmeS/AwdIhYLblmzlnqno+xPjZa6rqw3IEAAGgfQA4yMUww4tlZhpTP6cRnWnoIhICrrEs7li62Wdr/BNgq7o+1Pj5a6rqw3IEAAFAABikITtlH/ylzPBGuYNzAtFsExgP8ve8dH/8yN9lxv0aTh2mOdX4+Wuq6sNyBAABQAC4Qy6ONcaSRzONp587sWzGvQwOsk/AQ4JAutdnfZnTEu9BGL9jTVV9WI4AIAAIAPdIo7bWXvO5mefvMdZhC98/P/+8mKn34i75Xfn7p2GvAkHmM+S/3cLrnK89xBHjd6ypqg/LEQAEAAHgRDlOefXsEjfdSOM/05Nmus6ret5n5l6APclxro7/pcbvWVOuy1lsubX0WgQAAUAAeIBMMEsDmSV72cGv+o5z5DNmWVN+8ND19Jk/MX4W17fU8NT4PV1dc2XFrAQAAUAAuII8jeVNbOkdOCcQ5CaeWeWz7CZ37JIVEY+/m3PMfC8e2jtzivG7uhIAeigLOxEAri9jx7m4IsHg0K0Y6eaf7Wl/dOnSsoSgGUPNHuS4XmNVw13G7+tKAOihLOxEAGB0jZ3lZlrNsCfXXvY3Gr+vKwGgh7KwEwGA0bU2REpX9fjZPFx6j6rjfE3jd3YlAPRQFnYiAHDsmuPLWdmQZXfjd3C+DMtcY8Lpfcbv7UoA6KEs7EQA4Ni1Z5dnOVXeVnf8HZxvqeWno/F7uxIAeigLOxEAOMjkxOp4XeoWNgia2TXf9nef8bu7EgB6KAs7EQCIzC5f8mVIjvnDZNz/2tv9fsj4/V0JAD2UhZ0IAES2vq2O1TWZFHie3KDXbPxjrENXAkAPZWEnAgBLvFSm8uu/mhR4qmwuleNVHccljfXoSgDooSzsRADobemu/1EatVnfrjeLrRr/GOvSlQDQQ1nYiQDQVxr/LV55HBlyGOvDto1/jPXpSgDooSzsRADo6y//Wmdp2V3yMqWxTp1ljsSWjX+MdepKAOihLOxEAOhp68b/IDfa7vsEpCdm6S1+TzXWrSsBoIeysBMBoJc0tlt1+98lL7fJeTjWtYP87rxCuTouWxjr15UA0ENZ2IkA0Edm+6854e8c6frutkxwhi7/0VjHrgSAHsrCTgSAHjLzPtvyVsdjJrnxZiLcWP89yTX358dzDMGMxrp2JQD0UBZ2IgDsW57619pH/prSQKbu4++5ZRl+yVj/2pv7nGOsc1cCQA9lYScCwD5lYtmjr19M3djcJ3X/9PXf6tYnCR7+FrN191fGunclAPRQFnbSMQDkRpwlaHvclS5PzWlsbqG7/1R5De4t7xuQc636XTMa696VANBDWdhJxwBwLJPi0rjkOIzH5pbkTX5Z2nfLT/z3SahJF/otzhGYZZnffcZ6dyUA9FAWdtI9ABxLGEiXcxrT8TjNKBdwhjOyjK76PXt2i2Hgi3/PPyQz1rkrAaCHsrATAaCWG3VuAgkEWa41Qw9Bgkm697OOf89P+ue6pTCQm+7McwFSP36edrnsNeV3judnN2VhJwLA6Q6hII1NnryztC4XUSZ5HR/TS6UhS+jId2Q2/Ewbxcwu8wUOf6OEpfx9ZltNkLkne5qjwW0SAAQAAeDKcmNPA3SQHoQ05JU8yR//fzs8dWwpxziBKsHg2qHtXFnZINixJQFAABAAaCl7I4zXwtoSQmbdEIj9EwAEAAGAtrJqYrwetpBeoqp+sCQBQAAQAGgtje94TWzhy29fmtjJqgQAAUAAoL3Mxxiviy3khnwLuwWyDwKAACAAwGt5Ah+vjS1khUDHfR1YnwAgAAgA8F+Pv5sjBGSFQFYsVHWEaxEABAABAP4rY/DZ22G8RraQFQKZpFjVE65BABAABAA4khAw01bQ2bOgqidcSgAQAAQAGGQi3kzbCmdowgoBrk0AEAAEACgkBOTaGK+XraRXwgoBrkkAEAAEALhDtnWeKQSkLlYIcC0CgAAgAMAHpMHNrPzja2ZLVghwLQKAACAAwD3ykqaZQkB8/MT2wVxGABAABAA4Qd7cuPUbBEeff2OFAA8nAAgAAgCcKCFgvH629uR7KwR4GAFAABAA4AyzvEHwWJYs/uaREMB5BAABQACAM33ydI6XBx3LdZy5ClV9oSIACAACADzALG8QPJaJihmmqOoLIwFAABAA4IG++PeL15dQfV1tyQoBTiEACAACAFxgltcIj6wQ4D4CgAAgAMCFZnmD4Cj1sn0wdxEABAABAC4002uER1khkC2Nq3rTmwAgAAgAcAWzvUHw2LOXVgjwSwKAACAAwJUkBGRjntxYZ5MeCj0BHMt5MbYH3ZSFnQgAAP0IAAKAAADQkAAgAAgAAA0JAAKAAADQkAAgAAgAAA0JAAKAAADQkAAgAAgAAA0JAAKAAADQkAAgAAgAAA0JAAKAAADQkAAgAAgAAA0JAAKAAADQkAAgAAgAAA0JAAKAAADQkAAgAAgAAA0JAAKAAADQkAAgAAgAAA0JAAKAAADQkAAgAAgAAA0JAAKAAADQkAAgAAgAAA0JAAKAAADQkAAgAAgAAA0JAAKAAADQkAAgAAgAAA0JAAKAAADQkAAgAAgAAA0JAAKAAADQkAAgAAgAAA0JAAKAAADQkAAgAAgAAA0JAAKAAADQkAAgAAgAAA0JAAKAAADQkAAgAAgAAA0JAAKAAADQkAAgAAgAAA0JAAKAAADQkAAgAAgAAA0JAAKAAADQkAAgAAgAAA0JAAKAAADQkAAgAAgAAA0JAAKAAADQkAAgAAgAAA0JAAKAAADQkAAgAAgAAA0JAAKAAADQkAAgAAgAAA0JAAKAAADQkAAgAAgAAA0JAAKAAADQkAAgAAgAAA0JAAKAAADQkAAgAAgAAA0JAAKAAADQkAAgAAgAAA0JAAKAAADQkAAgAAgAAA0JAAKAAADQkAAgAAgAAA0JAAKAAADQkAAgAAgAAA0JAAKAAADQkAAgAAgAAA0JAAKAAADQkAAgAAgAAA0JAAKAAADQkAAgAAgAAA0JAAKAAADQkAAgAAgAAA0JAAKAAADQkAAgAAgAAA0JAAKAAADQkAAgAAgAAA0JAAKAAADQkAAgAAgAAA0JAAKAAADQkAAgAAgAAA0JAAKAAADQkAAgAAgAAA0JAAKAAADQkAAgAAgAAA0JAAKAAADQkAAgAPzq5/+8/p/i5ABgvwQAAeCN6uQAYL8EAAHgjd/+7cfyBAFgn775SQAoC7v56IufyhMEgH3K/K+xLeimLOzmk6fPyxMEgH169lIAKAu7+fLbl+UJAsD+/ObRD69v/XV70ElZ2M23z34uTxIA9udP/3z2+tZftwedlIUdmQgI0MNnXz1/fduv24JOysKOPn19QlQnCgD7YgngW2VhR1kSUp0oAOzHr//6w6tsAHd8/++qLOwqE0OqEwaAffjLv4z/H5SFXX3+zYvyhAFgH57+8PL17b5uA7opC7tKt5BeAIB9yv1d9/87ZWFnegEA9in39/Ge31lZ2JleAID98fT/S2Vhd4+/szMgwJ54+v+lspBXv/rDP7wgCGAPfvf5j57+C2Uhb7cH/r/PDAUA3Doz/2tlIW+ZEAhw2+z7f7eykHdy8lQnFQBzy8Q/r/29W1nIOzl5rAoAuD32/P+wspD35T0B5gMA3A5v/LtfWcgvPfne0kCAW5BVXOM9nF8qC6mZFAgwt9/+7cdXL970/Nf3cd4pC7nbJ0+flycdANvKq35/fGHS36nKQj4sr5OsTj4AtpF5WpmvNd6vuVtZyP2EAIA5pPG32c/5ykJOIwQAbEvj/3BlIaczJwBgGxr/y5SFnOeLf1sdALCmTPiz0c9lykLOlxRqsyCA5WWp3/fPzfa/VFnIw+QNgjkxqxMWgMv9/u/W+V9LWcjD5cTMLlTViQvAw+XlbN7rfz1lIZczORDgOjK8mp1Yx/sslykLuY7H3718M1GlOqEBuF+GVW3ws4yykOvJtpQffWFIAOBc6fI33r+cspDre/T1C6sEAE6Qe2WWV4/3Ua6rLGQZWbaSGazVCQ/A9296TC3xW0dZyLL0BgD80qdfPX99i6zvm1xfWcjyknD/+KW5AQB56jfRb31lIev58lsrBYCecu8z1r+dspB1ZZZr9g0wLAB08fGT52b4b6wsZBtZMvjnx14xDOxXdkrNtunj/Y/1lYVsKxeH7YSBPckKKG/vm0tZyBzyhkHLBoFblp38nnzvnf0zKguZSyYK/uaR+QHA7cg9ywS/uZWFzCdvwMr+AVYMADPLPSr3Km/tm19ZyLwyazZvxdIjAMwkq5iykY+Z/bejLOQ2ZGjAHAFgS3kYyRP/s5e27701ZSG3JTNr7SoIrCm79+UhZLwfcTvKQm5Tthf+y7+e2VAIWEz2KrFt7z6Uhdy2dMVlLM6EQeAaci/JPUU3/76UhexDZuFmGc7vPjdPADhf7h3p5jejf5/KQvYnuwtm7229AsCHZAgx3fzZiGy8j7AvZSH79vi7l6/+9E/vHADeyfbjedq3jK+PspAeMp6XPQUMEUBP2ab3s6+ev8qLyMb7A/tXFtKPIQLoIdd4rnUz+SkL6c0QAexPrulc2yb0cVAWQuRGkRtG9hbQMwC3JxuEZSWQ5XtUykKoZMfBdB1m3LC62QDbSlBPYE9wN5mP+5SFcJ/MGcjkIe8igG1lEu8nT43pc76yEM6RGcRZTZBlRNUNCriudO3nmjN7n0uUhfBQ6XZM92OGCiwvhOvIG/d07XNtZSFcSyYfZXOR3LzMHYDTpMHPbnyZwJeXfI3XFVxDWQhLSZelQADvy7WQayLXhgaftZSFsJYEgjzl5GknTz3VzRH25rjBN47PVspC2EqefnJTzKzmj74wqZB9yLmceTEZw7cmn1mUhTCTLG9KL0GemCw7ZHZZDZMAm3PW0jxmVhbC7LIpUZZBZejAagO2kNfmprH/9Kvnb3qtsjfGeJ7CzMpCuDXZtjihIJsTZc9zPQVcU3bYS2Of8yvd+CbqsQdlIexFbtSHYJAhhNzE8+RW3eQhY/XZZCfnS57qc+54eQ57VRbC3mUzldzcM06bLtwEA8sSe8jf+dB1/+jrF2/OAzPx6agshM4ycevJ9y/fPAUewoGeg9txGJuPTMbL3/HpD8boYVQWAnc7DCscQkIcGhyvTV5WJnzmOGeex+HYp3H3FA/nKwuBy2StdxqlNE6HhirScB3CQnTvVTh0xx9knsbhWGV4JscwxuMLXK4sBNZ3WMlwkNnmx+EhSx6PG8vKkqsfMkGu+s5jxw14HCbSHXhKh3mUhQDAnr361f8DYnNath4YI+YAAAAASUVORK5CYII=Azure Database for PostgreSQLGE.DSParallelLinesfalseAnyAnyfalseBrowserfalseSE.EI.TMCore.BrowserLower right of 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.EIRectanglefalseAnyAnyfalseA representation of Dynamics CRM Mobile Client ApplicationsfalseSE.EI.TMCore.DynamicsCRMMobileClientLower right of stenciliVBORw0KGgoAAAANSUhEUgAAAgAAAAIACAYAAAD0eNT6AAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAABcRQAAXEUBuS1iLAAAABl0RVh0U29mdHdhcmUAcGFpbnQubmV0IDQuMC4xMzQDW3oAAFcBSURBVHhe7d15fFTlvT/wZLIRwiaSbbIvZAES9h1kU0AExQ13LNaiXku1rd3V3tq6AFlmyc6+iEHF4oJr61JvF22rXlu9rVrxcnu76K+29lJ3Pb/nOZNgGD4GiOT7PHPy+eP9InwJkzNn5pPnM3POzMQ5jkNERER9DBxSbHjppZecuKw6IiIjXnzxRef9999Xv47w7yiyGxySvd5++20YRCIik/75z3+qX1H49xbZCQ7JTih0REQ2if69RfaCQ7KLfooNBY2IyEZ8NiA2wCHZg4s/EcWiN998U/0Kw7/XyA5wSPZAwSIiigX6nKXo32lkDzgkO6BAERHFkujfa2QPOCTz9NNnKExERLFEv1Qw+vcb2QEOyTwUJCKiWBT9+43sAIdkFl/rT0Resm/fPvWrDf++I3PgkMx65plnYIiIiGJV9O85Mg8OySwUHiKiWBb9e47Mg0MyC4WHiCiWRf+eI/PgkMxC4SEiimV8TwD7wCGZhcJDRBTL+M6A9oFDMguFh4golrEA2AcOySwUHiKiWMYCYB84JLNQeIiIYhkLgH3gkMxC4SEiimUsAPaBQzILhYeIKJaxANgHDsksFB4ioljGAmAfOCSzUHiIiGIZC4B94JDMQuEhb3r11VdJQfuGvIUFwD5wSGah8JD36A99ir7t+yq0f8hbWADsA4dkFgoPeQ8LwCfQ/iFvYQGwDxySWSg85D0sAJ9A+4e8hQXAPnBIZqHwkPewAHwC7R/yFhYA+8AhmYXCQ97DAvAJtH/IW1gA7AOHZBYKD3kPC8An0P4hb2EBsA8cklkoPOQ9LACfQPuHvIUFwD5wSGah8JD3sAB8Au0f8hYWAPvAIZmFwkPewwLwCbR/yFtYAOwDh2QWCg95DwvAJ9D+IW9hAbAPHJJZKDxERLGMBcA+cEhmofAQEcUyFgD7wCGZhcJDRBTLWADsA4dkFgoPEVEsYwGwDxySWSg8RESxjAXAPnBIZqHwEBHFMhYA+8AhmYXCQ0QUy1gA7AOHZBYKDxFRLGMBsA8cklkoPEREsYwFwD5wSGah8BARxTIWAPvAIZmFwkNEFMtYAOwDh2QWCg8RUSxjAbAPHJJZKDxERLGMBcA+cEhmofAQEcUyFgD7wCGZhcJDRBTLWADsA4dkFgoPEVEsYwGwDxySWSg8RESxjAXAPnBIZqHwEBHFMhYA+8AhmYXCQ0QUy1gA7AOHZBYKDxFRLGMBsA8cklkoPEREsYwFwD5wSGah8BARxTIWAPvAIZmFwkNEFMtYAOwDh2QWCo+0V199VW0K3j4iii0o49JYAOwDh2QWCo80FgAi70AZl8YCYB84JLNQeKSxABB5B8q4NBYA+8AhmYXCI40FgMg7UMalsQDYBw7JLBQeaSwARN6BMi6NBcA+cEhmofBIYwEg8g6UcWksAPaBQzILhUcaCwCRd6CMS2MBsA8cklkoPNJYAIi8A2VcGguAfeCQzELhkcYCQOQdKOPSWADsA4dkFgqPNBYAIu9AGZfGAmAfOCSzUHiksQAQeQfKuDQWAPvAIZmFwiONBYDIO1DGpbEA2AcOySwUHmksAETegTIujQXAPnBIZqHwSGMBIPIOlHFpLAD2gUMyC4VHGgsAkXegjEtjAbAPHJJZKDzSWACIvANlXBoLgH3gkMxC4ZHGAkDkHSjj0lgA7AOHZBYKjzQWACLvQBmXxgJgHzgks1B4pLEAEHkHyrg0FgD7wCGZhcIjjQWAyDtQxqWxANgHDsksFB5pLABE3oEyLo0FwD5wSGah8EhjASDyDpRxaSwA9oFDMguFRxoLAJF3oIxLYwGwDxySWSg80lgAiLwDZVwaC4B94JDMQuGRxgJA5B0o49JYAOwDh2QWCo80FgAi70AZl8YCYB84JLNQeKSxABB5B8q4NBYA+8AhmYXCI40FgMg7UMalsQDYBw7JLBQeaSwARN6BMi6NBcA+cEhmofBIYwEg8g6UcWksAPaBQzILhUcaCwCRd6CMS2MBsA8cklkoPNJYAIi8A2VcGguAfeCQzELhkcYCQOQdKOPSWADsA4dkFgqPNBYAIu9AGZfGAmAfOCSzUHiksQAQeQfKuDQWAPvAIZmFwiONBYDIO1DGpbEA2AcOySwUHmksAETegTIujQXAPnBIZqHwSGMBIPIOlHFpLAD2gUMyC4VHGgsAkXegjEtjAbAPHJJZKDzSWACIvANlXBoLgH3gkMxC4ZHGAkDkHSjj0lgA7AOHZBYKjzQWACLvQBmXxgJgHzgks1B4pLEAEHkHyrg0FgD7wCGZhcIjjQWAyDtQxqWxANgHDsksFB5pLABE3oEyLo0FwD5wSGah8EhjASDyDpRxaSwA9oFDMguFRxoLAJF3oIxLYwGwDxySWSg80lgAiLwDZVwaC4B94JDMQuGRxgJA5B0o49JYAOwDh2QWCo80FgAi70AZl8YCYB84JLNQeKSxABB5B8q4NBYA+8AhmYXCI40FgMg7UMalsQDYBw7JLBQeaSwARN6BMi6NBcA+cEhmofBIYwEg8g6UcWksAPaBQzILhUcaCwCRd6CMS2MBsA8cklkoPNJYAIi8A2VcGguAfeCQzELhkcYCQOQdKOPSWADsA4dkFgqPNBYAIu9AGZfGAmAfOCSzUHiksQAQeQfKuDQWAPvAIZmFwiONBYDIO1DGpbEA2AcOySwUHmksAETegTIujQXAPnBIZqHwSGMBIPIOlHFpLAD2gUMyC4VHGgsAkXegjEtjAbAPHJJZKDzSWACIvANlXBoLgH3gkMxC4ZHGAkDkHSjj0lgA7AOHZBYKjzQWACLvQBmXxgJgHzgks1B4pLEAEHkHyrg0FgD7wCGZhcIjjQWAyDtQxqWxANgHDsksFB5pLABE3oEyLo0FwD5wSGah8EhjASDyDpRxaSwA9oFDMguFRxoLAJF3oIxLYwGwDxySWSg80lgAiLwDZVwaC4B94JDMQuGRxgJA5B0o49JYAOwDh2QWCo80FgAi70AZl8YCYB84JLNQeKSxABB5B8q4NBYA+8AhmYXCI40FgMg7UMalsQDYBw7JLBQeaSwARN6BMi6NBcA+cEhmofBIYwEg8g6UcWksAPaBQzILhUcaCwCRd6CMS2MBsA8cklkoPNJYAIi8A2VcGguAfeCQzELhkcYCQOQdKOPSWADsA4dkFgqPNBYAIu9AGZfGAmAfOCSzUHiksQAQeQfKuDQWAPvAIZmFwiONBYDIO1DGpbEA2AcOySwUHmksAETegTIujQXAPnBIZqHwSGMBIPIOlHFpLAD2gUMyC4VHGgsAkXegjEtjAbAPHJJZKDzSWACIvANlXBoLgH3gkMxC4ZHGAkDkHSjj0lgA7AOHZBYKjzQWACLvQBmXxgJgHzgks1B4pLEAEHkHyrg0FgD7wCGZhcIjjQWAyDtQxqWxANgHDsksFB5pLABE3oEyLo0FwD5wSGah8EhjASDyDpRxaSwA9oFDMguFRxoLAJF3oIxLYwGwDxySWSg80lgAiLwDZVwaC4B94JDMQuGRxgJA5B0o49JYAOwDh2QWCo80FgAi70AZl8YCYB84JLNQeKSxABB5B8q4NBYA+8AhmYXCI40FgMg7UMalsQDYBw7JLBQeaSwARN6BMi6NBcA+cEhmofBIYwEg8g6UcWksAPaBQzILhUcaCwCRd6CMS2MBsA8cklkoPNJYAIi8A2VcGguAfeCQzELhkcYCQOQdKOPSWADsA4dkFgqPNBYA77l+7eOpykXKRPTv5F0o49JYAOwDh2QWCo80FgDvWfm1B9K/cM39Pz/j83fVxmfWjE3MrB+blBkYjL6XvAVlXBoLgH3gkMxC4ZHGAuA9KfkNGWnFTc8m5Qb+TxWA11UBeF0VgAXoe8lbUMalsQDYBw7JLBQeaSwA3hPnr8mI8699Ni6r1onPrHMSMmu1Jeh7yVtQxqWxANgHDsksFB5pLADe8pXr7s0685L2M5MLal/RBSBOFQBdAhQWgD4AZVwaC4B94JDMQuGRxgLgLVd+ffeJy6+889HBZY1vxWXVqwKgZASVEAtAH4AyLo0FwD5wSGah8EhjAfCWMTPXnzhyatujybn1b8Vl6mcAWAD6EpRxaSwA9oFDMguFRxoLgLcUj287o2Bs62vJuYF39dP/LAB9C8q4NBYA+8AhmYXCI40FwFv8o1uWZ1U1O0m5gchtzALQp0Tn2wQWAPvAIZmFwiONBcBbfP61yxUnPmutun15CKCvQRmXxgJgHzgks1B4pLEAeMcXrnqoumhi29q47Br3zH8eAuh7UMalsQDYBw7JLBQeaSwA3jF7yc65/qqWjZGT/0JKgAWgj0EZl8YCYB84JLNQeKSxAHhH1sjmpWkFoTvjMvRt26CohZ8FoE9BGZfGAmAfOCSzUHiksQB4R/Wcja25Y1v+6S76evHP4jMAfQ3KuDQWAPvAIZmFwiONBcAbbgj8Z0JmZWjHoGL91L9+5N/x6J8FoE9BGZfGAmAfOCSzUHiksQDEvnln3+Wbe9au1KTMmp0+/fS/e/yfBaAvQhmXxgJgHzgks1B4pLEAxL7Rs7YkKX5fdvCHkYWfBaCvQhmXxgJgHzgks1B4pLEAxL4LPr+nUnkoZ1TrG+4JgHrR158DoG9jFoA+JTrfJrAA2AcOySwUHmksALFv/LwtE5S/DS1rUAu+vl1ZAPqq6HybwAJgHzgks1B4pLEAxL6kvLUTkvJq/hbvrz30NmYB6FMOuf0NYAGwDxySWSg80lgAYp96tD9B+Ru6fVkA+hZ4HxDGAmAfOCSzUHiksQDEtotX3X/CCUt3tibkhN4+8LR/VywAfcoht78BLAD2gUMyC4VHGgtAbJt16s4VY+Zs+01CTvCDuGy12Helb2MWgD4lOt8msADYBw7JLBQeaSwAsW1wUfMVAwoaXovLrvnQvU1ZAPq0rtk2hQXAPnBIZqHwSGMBiG0pecFvJecG3ovLqv3YvU1ZAPq0rtk2hQXAPnBIZqHwSGMBiE1TT9rpU6oHFjes86nFPh4d/9dYAPoUeB8QxgJgHzgks1B4pLEAxKap89uTpi5o/0p6Zcsv9Gv/4zPUQu++B0CUGCoAbRseT1AGK4no3+nwDrn9DWABsA8cklkoPNJYAGLT1EXt/aee3P5k3tjWj+My1jpxw9TtGfsFYJAyRTkO/Tsd3iG3vwEsAPaBQzILhUcaC0Ds+feaXySetvzujOPLm36Wmh9Si7u6LTNq1O1ZG9PnABSP31hVMn7jDzNHte5Jrwytzxu5+nJlCPpewqLzbQILgH3gkMxC4ZHGAhB75pzanlI1Y1NBQlb9L9wFXh8CyATvAqjFSAG4vu6p9HEnbT9/QFHojf5FwfcHFNe9PqR0zT1KLvp+wuB9QBgLgH3gkMxC4ZHGAhB7MitDw4aVhebHZwaej3z4T52TkBlQJaDjUX9XMVIAvnT94yfMPnNnS3z2mg/iMtc4Pv9aJyl/7StKCfp+wg65/Q1gAbAPHJJZKDzSWABiT97YxkW5Yxr/NyUv8G5cVkDdjgHHl1Ef0wXgjEt2XzfztB3/SMiuc+LT6x2fuk5JeYFXFBaAo3DI7W8AC4B94JDMQuGRxgIQe9KKw2ekFYWdBL9e8DX16F8/E6Bv0xg8B+CsKx5OKJy4fnVWVYsTr89jUGXGlx1wkvOCrygsAEeha7ZNYQGwDxySWSg80lgAYsulqx4uL5646frII//O21Et8p2vAIixArDy6h+nKAuzRrXtjlyXyLkMPn/AScoPvqKwAByFyD40iwXAPnBIZqHwSGMBiC2fu+LBb884pf0VdFtClheAz3/xkYxLvvjIs9Wztx203b6ceh4C6IGu+9AUFgD7wCGZhcIjjQUgtoyavimUN7r1bXRbQpYXgMxRLRnKs/qQRtft9vlZAHqi6z40hQXAPnBIZqHwSGMBiA033PzzZKU4p6ptZ1rhwYtltywuAKdesLt45uKdVyTnhl+L/ihjFoCe6boPTWEBsA8cklkoPNJYAGLDRV/YM3D5yj1Lhpa3/SguO3Twsf5Po29jiwvAjMW3nTxp/q2/6l/QtD8uS21jl213DwHwHICjFp1vE1gA7AOHZBYKjzQWgNgwKLduqLIyMTf487icgxfLT6VvY4sLwLDK8IVDK0IfJOYEP3ZPauyy7SwAPROdbxNYAOwDh2QWCo80FgD7BdY/l1Awbl15al7w4QR/4G/RT5d3y9ICMGLG1lHHlTWuTsrVn2RYq7bz4Hcy5CGAnum6D01hAbAPHJJZKDzSWADsN2vpztTMkc3TknICf/Tp2y3jU972F7G0AGSNarp8QHHoycjL/jo+x6DLdrMA9EzXfWgKC4B94JDMQuGRxgJgv6wRDf6BRYEL4jJq/hKXrhZL/cE/XZ4u/1T6NrawAKhti08rrN+Rkqfvg/q6qD+jtp2HAHomOt8msADYBw7JLBQeaSwA9ssZGf5cRkXwNZ+/5gOfeqTs04cAohZMSN/GlhUAtV0JyiD1CP+OeL3w621kAThmumbbFBYA+8AhmYXCI40FwH4D8kNX988LusfK49UjZg3dlpBlBcCXUZ+v1MRl1r0Et7dD5BCAKgB8K+CjgvalNBYA+8AhmYXCI40FwG7jpm+rTMtrDMal60/7U7dZ5lp1u2mH3paQRQXgnEvu81dM3XRxQlbdW9En/UVjAegZtC+lsQDYBw7JLBQeaSwAdlMFoCl7ROv/6tsq8si/E749D2FXAVg++7Sdv07Mq3n/cNeBBaBn0L6UxgJgHzgks1B4pLEA2G3o8Ka7+ueH39HPAMRlampB18BtCVlUALKrWq8ZVtH8VmJ24OP4w7yUkQWgZ9C+lMYCYB84JLNQeKSxANipenbrYGVKv/zwz33ZegGPfO5/hFo8o06ag/RtbEEBmDB3o0+ZNLgktDlRLew+XWQOcx14EmDPROfbBBYA+8AhmYXCI40FwE7l01oqlHBKfui/D/7o36NkQQGYumBbasWUtpuOGx56IV4f+z/M8X8t8gwA3wfgaKF9KY0FwD5wSGah8EhjAbBTdnXLXOWt5Pz6D6LfJOeoGC4AZ6/YkzRpwY7slIL6x9Sj//d9enuOoAT4/HUsAD2A9qU0FgD7wCGZhcIjjQXAPiNO2DR4yPDw+an5AcenXyN/BI+YP5XhAjBp/rqJ4+e1tfcvCr3uyw448frZjEx9AuDhCgCfAegJtC+lsQDYBw7JLBQeaSwA9ime2DJ7aHm4NS5dLZIZ+naKHBc/avo2NlgArr7+sYHVc9avKJrQ5PQr0J9g2FEAOhd/tM0deA5Az3TNtiksAPaBQzILhUcaC4B98sc21maMaFCLt360rBfM2DwHYPmqB6pLp268CW7XYbgFwKJnAPrnBhOUVCUe/bst0L6UxgJgHzgks1B4pLEA2KdfbkNtco56xKxfK3+gBODb77AMFoCMkc3fHFQa7vYd/z6NbYcA1MI/VvmWkoX+3RZoX0pjAbAPHJJZKDzSWADs0b9odZpyUUJW3WPx+ql//a5/7glzh95uR8xAAaie2ZaqTBxQFLwzKaf+Xbhdh2FTASifvOmsjIqmLYnZdb+Oz6gNxqXXzkTfZwO0L6WxANgHDsksFB5pLAB2uP6WnyZWTG8r7lew9rGE7Jq33OP/mWvUbaRk1xxyjPyI6NtYuACcfPF98cUTWrPzRzf9oF9e/W/dAoO27TBsOAdgzuJNA5TJxePXPXx8eZPjfhaDKmbx6XXfQN9vg+h8m8ACYB84JLNQeKSxANhBFYDjTj7vrrnJuYGX4zPrP3ZP/nMLgF781ddgkTwsfRvLF4CkYRUtY/vlhl5NyK77MLL9Udt1BCwpAOOU/8kc0fBBfHZAbVfQScgMOYkZIRaAbrAA2AcOySwUHmksAHaYf0b7CdMWbr+9X0Hw7+5Z/67Os+W1gxfII6L/r3ABmLOk/dQJc7f+uF9+4O34zp+Ptu0wTBeAKYt2LKmavfGezBF176bk66xEtku/ikFhAegGC4B94JDMQuGRxgJg3ubbfjNo/NwtlxWMbf1rUm7gfXQ79ZhwAaiYsunqovHrnaRc/bM7fj7arsMwdQ7AovPuSlROrZq15XZ/dev+BH/dx2D7WAC6wQJgHzgks1B4pLEAmPe9Nf9RUTxx3S1xGfq4f8ej/mNFsAAMGt6ckegPfc/X+WY/n6kAyL8T4AXX/Lj/WVc+WDH39NufLp6w3onXr77Iblbbo/bfwdvHAtANFgD7wCGZhcIjjQXAvJHT1598XFl4R+Qp/5guAOtSCsJ/dT/pTxcAt9DEzjMAqgDMP+eqh3+fO3bdv5JzdImpUyUAbh8LQDdYAOwDh2QWCo80FgDz+uXV/yDJX//yQYtN1DHxHtGXI1AA5i7dUaR8c/Dwxt8n5OhHy/pndxaZLttzFKTPAVh80R1Lp512267hJ2x1UgvD7uIf2f6O63Hw9rEAdIMFwD5wSGah8EhjATBn6vytg5VZKTnBJ+Iz6tWjTbW4gNvoM+nlAnDi6Q+ljJ61bf6oGZv2phWH3nZPWETbcZSkngE474oHBihzpy3ecVfJ5PX/QtsCsAB0gwXAPnBIZqHwSGMBMEct/uOnnLTld8eXtv4rPks96tQvNXPf+OcYHgbo5QIwa/H9/mEVGy9Tlx/5ednHZtslzgFYfP7t8ededv/Icy67/79LJm2J7CewLQALQDdYAOwDh2QWCo80FgBzhg4PTlH+X3Lu2sjr5d2T5/Dt1GO9XADSChq/lJIb+i/3eD/6+T0k8QyAKgBnzlm642e5Y9a/k1rYUWCODAtAN1gA7AOHZBYKjzQWADNOPOP2cRVTN96c5K9/Nz57rbot9FnzXQ4BHHzMuWf05fRSAaicvSVNOXNgceNDCe4zF13O+kfbcpR6+xyAKQu3nFY9e+Ou4kltTqJ73oIuMArYFoAFoBssAPaBQzILhUcaC4C8TTtf6Td90Y5vVEzb9GdfduijyKf9qYWlswD09I1/ounL6oUCcMEV96TOOHVHddGUDY8NLG18K7Ld+ufon3dstr23CsCkk3YMVKqrT9j4SHZV0zuHHLIA2wKwAHSDBcA+cEhmofBIYwGQpRb/BGVk0cR1bUk5+q1y6z+OnDXfSd0u9heAMSefe/st/YuCf47Pqv0ocs5Cx89zt7/LNvRQLxaA2cqfjy9pficxK/DxISctgm0BWAC6wQJgHzgks1B4pLEAyLr4iofSll/+UKB86saXI8f98e1yzBzjAjBv6V0peeNazssc1fRfCf76d475SYsdeuMcgLFztpxXNnnDw8dXNDvJufpZlx5vNwtAN1gA7AOHZBYKjzQWAFnTT75tyOT5O57KGd2q9v+xXzgPcYwLQOmUDfOGlDVsSVSP0A/9WceuDBzLAuCvbk1VFuSPabs3c0RTxzZ2wj//MFgAusECYB84JLNQeKSxAMjJGnlz0oDi1YVx2Wt/7e5//Vaz+qlz/DTzZ+f+DPXnMSgAZ154R4IypHBi291DKxojl3tgIe24P3UWALQtR+lYHQIYWlKbkl4RHpk5quWZ/gWh99xXK+iPV9bnK2Tgn30EWAC6wQJgHzgks1B4pLEAyFEFYE565c2PJ+TUvqUX/shHzMIF5tjQt/GxKwCVyi7/6IY/J+bqt8jV5eXQ+5MLbctROoYFYOmQ4tr/TM4L7Pdl138U2b7ObcU/+wiwAHSDBcA+cEhmofBIYwGQcfqlu4dkjWhcOSC//l++rNoPRZ7+145BAagc1zygbFLrouGT2/6cVhx6X19mfMZnOoZ+WJ/lEEDrthf7KcNzq5ouS82r3ZOSV+vEH9ttZQHoBguAfeCQzELhkcYCIKNqzpapw8pbGxLSG9RirBYj/bp5iRLwGQvAVdc/kZJf1TxpQEHwxvjs2nfcR8360b9++jz6EMAx1NMC8OXrHki78Ip7q5ZcuPur6RUNzyf59eXp/a0d+nN6iAWgGywA9oFDMguFRxoLgIxhlc03DSgO/9H9wB/3TXMEFn/tMxQAtfj7lPysES3BfrnB9yOL/poO+rKjftYx5B4C6FkBqJ57xvZ/Tyuo/78Ef+Aj91CLu/irbdflBfysHmAB6AYLgH3gkMxC4ZHGAtC7qk5o76eMTC0M356QE1CPoLvu/45FCR9n/uz0z/gMBWBoSTBNaUzND73qy1aX4W6vLi5R5QX97M/oaM8BWHLhLp9S6B+z7tqBJY2/T/DXf+Re1oFFv+PrqJ/TQywA3WABsA8cklkoPNJYAHpXVmWLP7Oi5cbk3MALaP/3uh4WgIkLtxRXz9n4xbT84KuJ7lv9dnPSXy+IHAJQBSDv8AUgo6oxLX1kQ/mwysavpeSHfxaXpcsKvtxjhAWgGywA9oFDMguFRxoLQO854+JH+heO3TBrUGHorweORYPboFf1oACMW7hpgFr8PzfihA3/TC0If6g/qtjnnrcgt/1HWgAGlK/vN7i8adSg4eGrfP7aVyOHWHRhOfQyjyEWgG6wANgHDsksFB5pLAC9RxWA2dMW7dqUnFu7P/KufzFTAE7PHdd8Z3Je4KPErLqPI8fQrS0AE1OLmm9JyWv4iy+z/v1IAegALvcYYQHoBguAfeCQzELhkcYC0Hv81RsvTR/R9mpCdt0H8Ni5hKMoAGPnrklRSoeOCIdTC0P74tLrnHh1Ge5L6AQXf+1wBeDyqx/MUW4unrzxLp8/8FtfZo0TWfz1dvb6WyyzAHSDBcA+cEhmofBIYwHoHRUTAyNS8wON8VkBtTCpRVjv72P1IT9HSv/MIywA37zpybS5Z24fkV6x9prE3Lpn3BPm0jsvpzZyJr17HTpmvay7ArDonF3FJy+748qFZ9/+ZuQtldWCn766Y/HvUgDA5R4jLADdYAGwDxySWSg80lgAjr0x05sTyyYE6ocOr/uDu5/VI+lefkr60x1hAbjqukfL5511+1eTsmv+HnmPAnBZgiIFQL8M8OACUDqxOXHBWXd8bdrJO95Jya37WOz9FA7GAtANFgD7wCGZhcIjjQXg2Fqw5I60OQvbKwcUhh5JzKl/293Pw/QirPe3+EJ1xAVg8PDQJQNKgi/HZwfdd/ozVlg6+Px1qgDUqwJQf6AAqMXfp1ybXd30zOCyxo8SsutVAcD/v5exAHSDBcA+cEhmofBIYwE4torHNYwqGhtuSM6t/5/4rHpHHwJwnwEQPov+gMMUgIGFa33Kecm5tff7svWb5qjvPXAsPeqyBOlnAJLzAq8obgEondhSWjKh+dvDKhqfSy0I/0u/1O+TkxPxZfQiFoBusADYBw7JLBQeaSwAx86is3am5lSFzhlWoRav3FonXi+oWaFPFn+9UB18LLl36du4mwLgr2oanD2qcWJaQc1TSTn6ewOR9/h3t7UGX6YQX05AFYCgKgCRQwDFE1oWF41vdtTirxb+kNpOtV8z13ZQ2wsuoxexAHSDBcA+cEhmofBIYwE4dlQBGFU4bt33fH61OHUuFgfeia7DwQtJ79I/r/sCMF8VgNdT8gPvRT4hT/+fjv8nva1Rok8CzBnTsjhnTLOTkq+uS/R2ym8rC0A3WADsA4dkFgqPNBaAY2dQUejq1PzQb6XfNa9bn1IAcqo3LT++ovXR1IKgu9jC/2tQdAHwqwKQPbrZSc63Yt+yAHSDBcA+cEhmofBIYwH47AbmhlOUCYlZtbvi9VPn6UaOS2NRBWDE9B0DlKUZleseHlDU9HG8+7a5LABHiQWgGywA9oFDMguFRxoLwGdz5dd+lFBQvS5vQE6oJSFr7R/iMlY7ccNUCZA+3o/o2ziqAFRO216svHzc8GZHv8VvQmaj+j61qKL/bxA6BOB3C4C6LuD7hbEAdIMFwD5wSGah8EhjAfhsVAHInX/WnRek5AT+Kz6z9t3ICXRqkdCPqvHiIUffxlEFoGzqumLl5ePKw068Pu6vz/q3YVujsAD0THS+TWABsA8cklkoPNJYAD6bEVPbTi4e3/Jwor9+f2TxVzr3L1485OhtiCoApaoAKC8PKVMFwP13S7Y1CgtAzxy47xnEAmAfOCSzUHiksQD03Jeu/VnViOkbA4OLA47PfTQdVQBscEgB2KAKwIaXBw9vwN9vCXQOwIECAL5fGAtAN1gA7AOHZBYKjzQWgJ5TBeCuWWf88EP3GLptC38nDxUAngR4eGBbxbEA2AcOySwUHmksAEfvW7c80V8pL5uy5dHjy1vUIqv2JQvAMcVnAHoGbKs4FgD7wCGZhcIjjQXg6FWdsK5Q+W6/vNDv4zLUAhv9kj983Fie3pYjLQDo/xvEcwB65qDb1BAWAPvAIZmFwiONBeDo5FQEU44rqT9xSHHd/yTmBN5x3/THltf8I3wGoDewAHSDBcA+cEhmofBIYwE4OqoAjBxUGLo2ITv8ri+79qP4rLVqPxr5SNojw3MAegMLQDdYAOwDh2QWCo80FoAjt+o7Dyf19wcuS8qq/3V8dv1H7uLqPvq3dPHX+AxAb2AB6AYLgH3gkMxC4ZHGAnBk8sY0pCgLUnICu+P1Z/u7L/vTi6vS+eE0+HixOfo2PtICgP6/QTwHoGcOuk0NYQGwDxySWSg80lgADm/ykm2+vLGNuemVwef6F6oFwD3rv/OlfwpeJMzTtzELQG9gAegGC4B94JDMQuGRxgJweKoATBhz0uamgUUNf03wdx6DVgtB537Ei4R5ettYAHoDC0A3WADsA4dkFgqPNBaA7o2etal/ztjmCzKrmv6QlBN696CFPxZ47hwAngTYHbCt4lgA7AOHZBYKjzQWgO4Vjm8eP6A4GPDpp/rdp/4P3YdW81AB4KsADg9sqzgWAPvAIZmFwiONBaB72dUN6wcPD76tP+c/3qbP+T9SnnsGQF0X8P3CWAC6wQJgHzgks1B4pLEAYOdfurtYWZ8/tvm1pFy18GeoAqAXUxvP9v80+jbmOQC9gQWgGywA9oFDMguFRxoLwKFmnrojbcrJ2xdMXrj978dXqIVSPfqPnPGvfvnzHAARfAagZ8C2imMBsA8cklkoPNJYAA5VPXtzRfbo1q/H5wT/6e6nzg/64TkAYngOQM+AbRXHAmAfOCSzUHiksQAcamBJ+Iv9C8N/9GWFPjzwXv9KfLb6Wj8FDPajtfgMQG9gAegGC4B94JDMQuGRxgLwiXELticrV2aMbHkyyR904t33+O+yvzoLQKzQ2+ypcwBaeA7AYRx0mxrCAmAfOCSzUHiksQBEVM5c169i5vrS4dM2PT2sosXx6YUza40SVQJijUeeATioAIDvF8YC0A0WAPvAIZmFwiONBSBCFYDC4VPbrkzyh1+Ozwg48e7T/vp4sy4Ch+63mOGpAsBzAA4HbKs4FgD7wCGZhcIjjQXAiWvc/OK0Uy68+8aknPoX4rNq98dl1EZe868/9CfWTvqLxgLQG1gAusECYB84JLNQeKSxADhxJ56x6+rK6Vuec8/21y/5UwUgLl3tn4y16u8drwCIVSwAvYEFoBssAPaBQzILhUdaXy4AU+e3JyulQ4rCO/vlRJ721+/45z7ydz/md7Wi/o5PBLOfvo2PtACg/2/QpxcAdV3A9wtjAegGC4B94JDMQuGR1scLQKny84yK1v+Ld4/3d9036hd959d4EbCf3nYWgN7AAtANFgD7wCGZhcIjra8WgPlnto+ZvGDbD7KrW9/sV6AWf/3IH+yfmOeRQwB8I6AjA7ZVHAuAfeCQzELhkdZXC8CI6RvOL57Y9kJibv177tP8LABWYQHoGbCt4lgA7AOHZBYKj7S+VgAuverR+LTicGqCv+4bvmy10Oiz/NPdBRI91Rvb9G18oAAEeQjg2GEB6AYLgH3gkMxC4ZHWlwqAWvz7KYUDisPNCTn1r8apAhDZD+qXuoZ/2ccufZ0y1CNmFoBjjQWgGywA9oFDMguFR1pfKgBlUzdUKOH+hYHX9KN/tD88RT36d09udJ8FqI/5QwB8GeDhgW0VxwJgHzgks1B4pPWVAjB27vqCwvEtV2WMbHJSctV19+ox/yjx+lkAXQAyY78A8ByAwwPbKo4FwD5wSGah8EjrQwXgppKJLfvd9/hPV4u/frMfsD+8RheA+IwGzSPPAATh9wtjAegGC4B94JDMQuGR5vUCcNGqe4Yo36qYvumZtMKwWvg7Fn998h8+vts7Duxz/XXXv3cWkc5Z17+D/+e+W2Hn93T++cnXCTkBp5+6noPLmpzjK1v+L2/cxtcmnvzDn00+Zfd0vT9Kp65XBWD9y0OG632hL6vj/6NtNojnAPTMJ/cHc1gA7AOHZBYKjzQvF4DJs7YOnDRv65SJC7f+ImNky373hDj91H/nAop/ufcOvUC7P7fjZ+uFt3Px7fp399CEFvV9ij5vIbUg4AyrbHQKJ6z7sH9h8FeJOfU/SisK/yh9ZPOPUgtDtyXlBtcNLG1clzGqdV3euA3B0XNv++6FV//H5cu/8tMCvU/KpmwoViIFwN0X6rKl98URYAHomQP3J4NYAOwDh2QWCo80rxaAq7/7eEL1tE3VBdWt1yb46/+Errsod7Fdq77uWNzdRV0fzw4palE5sNDXOPHZa9XiV+sMUot0Uk7w9bjM+n3q3/Yl5dbuyxzVtG/8Sdv2nX3JD18ZNWPDVf5RLafMOW3XKd+88elTrlvzaz/aF9rWnb8d9p3vP5Y7Yc6W6WUTN+4dog8B6BMhOwuAZXgIoGfAtopjAbAPHJJZKDzSPFwA8nLHtV6TkFOnF/8Poq+3uM7PF9DPQrhP5+vPHgg4SZlBx5ehFuNM9YhcLXp6UU4rCDmjZmx1rvzGT5zFF9z7BVUAKtVCXakKQKUqAJXjT9xWueySH1aMmL7heH9Vy8DZp9058Fs3/XKgKgCJaF9oqgA0XPuDx1844eQtLw0ZHnpP7ZfI4q8/9MjCEsCTAHsGbKs4FgD7wCGZhcIjzasFIKOi5aq0wvAv3OtpywKnt0OVAJ/6OrUw4AwuDe1Pyw//Z+X0W5+tnLnjdlUArlYF4OqBReGrJ8zbcfW/r/m1VrB++/O+b9/05IBLrn5wxKRF7dU5Y9eNK5zQMuOEpXd+e8KC9rr8iRvr+hUG6xL8gbr4zPq6uMyaurgsrVZ9XeeauujWVyYt2ObkVDc7SXrx73gWQn3/odtpgU9/BoAFoDtgW8WxANgHDsksFB5pXisA2eU1g5U5KTmBJxKy9WLRzYKBj+8eRtfL6Dymr+bu3/WfXemfUevEq/+jn84fUtH4ZnJu8NkhpaFfZo4MP+4f07BzSHnjdcsuf/Db31r99KKLrvxJklI+7ZSdo0sntU2snrN9QdaotgVDyppOyaxqOXfErM3XZY9u+/7A0oabjysLNYw8Yev/lk3b4mSManWS8wKOT19f9yV/ndulF3lNbYc+4a/zpD93FvnafZnggevTA3AffXY8B6Bn4G0kjAXAPnBIZqHwSPNgAZisvJ6SW/NBZBEOR66rXrjxL/OjEp9doxbNzmP5t6hFVH3tvtueunz16D5efe1zn+rXb8JT6yT41zpJ/hpn/IKtzqKL7vqPqSffduYP1vzHSZu3PeeelNeVWvyHKrXTFu3cWTpp3eOqADiqADj9CtR16Lod6vroy47QX0d0vN6/Q+c26YVf/5vW+X+6UtcH+KTcRFOX01XX7TqGWAB65pDbxwAWAPvAIZmFwiPNSwVg7Nyty0snb3gqJS/4XkJ2zceR66gLgPqlHXW9e65jEcxUC5Fe6DsX3HQ1VwuqLho+tUhMWtDuqEfy7aoAnKQKwEnj5m89SRWAiVNO3pFx49qfDr3mu09edv5lex46vrTmocTMtQ+p//9Qgj/46JDhja8NLA7+uX9B/ZsDS+qd1NwaJ1GVjoO2ocui71ILvBaXrrdD/9nxd3fx1wVF0dvW+f/dMtSV/rfOkxT11x3f27VMuH+qedfL6UU8B6BnwLaKYwGwDxySWSg80rxQAC64/L4U5fzq2VseGlbZrB6hd5wp7i5YauGKus6fTeeCqL5WC26SP+gMKGp4b1Bx+NV+BYFd8Tm1tT5/Xc3J591dc+mXH73wwi8+VDn15O1Thk/ceFF6efNX1OL8FVUevjLyhK0PjZu3zUnLr3F87kKtt1M/au/y6DxrrePLXKO+/vQC4F5H9/9r6u/usxCa/rrj3w8s7OrvWnQBOLDod/meAwt/V/qyOnR+Xy/hOQA9A7ZVHAuAfeCQzELhkRbrBWDs7FtTZ5yys3LRebueHT5lo7pOeiHtXLz0YrWm47qq2aFP5XahvufAgtjx/Qf2k/468vd4tUgn+UPOwOKA0y+v/vVBReFXcqrani6furFpxqk7lyy74oGCoZWhokGl4YqxJ956yvQlO79RMW1jOH/0ut8dV9oUeYSunz1wF1i1sLtvTKS/1qVFbbP+umPxju/4+fFq+xJyg05yQdBJLQo5A0rCHw0uCX+Q6K//iyoK+1RRUGr2Jfjr9yXlBvcl54X2pag/U3LD6uvw3oScut/1KwruTSkIvpqYG/i9uozX+heH9nVKzq1/OTkv8Id+Ber/5au/5wXdy0n0B/clZNeryw7sU9um1O3zZdf9SX3vW2nFYaef2p6kvICTkKO22d1veh9FU/MD+/Yw/+5e38hcF4DEvMArSuQQwOhmHgI4ApF9aBYLgH3gkMxC4ZHmgQIwZtSMraFBwxv/nKgWyQMLi7v4q+voPgPQAf8y76C+Vz8Vnt3xdLn7iFw/La7m7td60daLcq2TXtnoLFy2S7krPOu0O+arApBdMW3T0Ku///OLzrriwfXHVYR+qArAi6n5ob8kZAfeTPAH31J/vu/T26AfqeuF/sBT6h3bqOjL/mRe4xYAfZZ+v/wGZ9jIVqd06npn/Pxtztwzbn9v6fK7/jJ8yoYb+xWEVw4sbVo5pLx5Zfn0zSunLNqxcvYZO1cuXXHvynNX3rvyvJV3n3vKRbvHXfXdx5d98drHTj/vigemff2G/7j4Wzf+dGWHL1zy5Yfnnv9v9yy+6Iv3rDzn8vtWnnzB7pXTl965snp++0r/2NaVQyoaV6aVNKxMym9YmVnV+p0xJ23fM3PpHU7V7C1OwbhW57iykONzD1PobdfXTT9K77iO+jq5+1XvX30d9Uzr3Ad63rHv3ftk5P/GuwWgXhWA+o4C0LjYX90YeQbgkNtOHAtAN1gA7AOHZBYKj7RYLgDLrtgzrXru9lsGFDe97PMH3ok8hR31dPmBBeegX+CHchff1ZFFqfNRuF6c1Fw9CnYGFTV9vPTi+9498exd7RkjG1ecftHdK879wp4JI6asX5ZZFt6Q4K/bkFHV+pPsMW2vpeTX/CUpN/CeT5cG/VG8mSH1p1rU9GW65wroy9Y/Vy2cec3O0BFtTvW87c6ii3b/LXv0um+rArBCFYAVqgCsiM8MrEgtaFiRUdW2omLmxhVTTtmx4uTzdl18/mX3nFM1a3NVWnFj4dDKtsKMUesKJy68rfCUC+4qPOeye4q+dsMTZd+56fGSW0I/nRdoe/rWG+t/8sB31zy+57urn7jjhponH7mh5olHbw7+7IfNW15Y27rthapbGn6aft3qRwu/9v3HCy/56iOFp116f+EJy+4uLJ62oTCjurlwcHlTYUphU2HehPWVUxa3zz3xnLtWjDtp+4qSiW0rji8PrUjw16xQ+1htd+CAaUt23Dnj9Nv+UjRjvTOovNFJzFX7wX32I7Jf4/TJlBl6n+uipfe5Wtzd/RV0fP6g/v5XFLcA5I5pXZwzutVJ4TMA3Tr4vm8GC4B94JDMQuGRFosF4OrrfpailE9adNuNOWPW/WfkUaf6xawfOR9SAI6U+n8ZN6tH3EFFL9a17/oyA38cUt74m2GVzY9mVbTd/u2bfv7QNTf85KbRczctS8iqW+bLDp4zsDC0YXBR0C0J7jaohU0fu9fH5xPUAp+S2/CRKijvDChq+Gt6Rcu+0kmbXu1fGLxPPcptj/M3ticUbWjPm7SlfdHyu9uvq32q5cbwr0df8a1H/TOX3pY7oCyYe/7lu04469LdS9Uj7mXlMzYuy6xuXZZW3LAsPrNmWXyGVqvUL1OlZZn6+cvUIrxMPcpe1r8gdGFybuC80XO3/vvyVXs+OPvSu5zTP3enc8bn7nLOWPFD9fUu/effz7r0gafKp22+xpdZu8ynLk/Tl632h1Kr1LmXq/aJKyEnsCytpHFZ1uiNy0acsG3Z3LN2LVt4/u75vtya3LTh4dwxJ7Xnfu5Lj/vr2p4fckvDz86+/NsPBSaevqM9Y3Rre3J+Q7ta3JXa9rSS4AODy4K/GlBYuy8hq+Z/kvyBf6p99V5idviN5JzQH4eUtezLH7/5yYLxm91XS+SOWb84d/R6VQD0Oyei208UC0A3WADsA4dkFgqPtFgsACuveSLr819+7LrsqrbfuCfCHfSIvad0cbhFn8H/gVrM307Mqnst1R/csfi8e6/79k2/XJA7ujmjeta606acsuXeUbM3OqoAqJ8XKR76hD1VFpzEHP2oNfBhfHbd/oSs+n/2zw/9I6Oy6Y2yyW0vj5y+4b6lF9+zKbTpxaa6db+pPH3FntTq2Tv6T1iwbVDZtE2DMka1Dp5wcnvGV7730wXnXn7/eeMXbFvevySw/MwVd/zotIt3vTl1yU5n+LSN7mv++xc1uD9TFQBdVBR9/TsKiEttW+f+cOlnHbrq+r31atvrFHUd1OXpExLdkw5d+nv1/498nz4coY/3pxU3OplVG5zyGVucE5be4cxbtuv5+Jya5akl4eUVM7cvX3rxA+de+e0nZp79hfsLji9vGlwyed3gsmmbB1bN2pJ24pntqd+t+2VqXdtvR5132YOfHzN76+aBhXVbBpeEfple2bzvuJLmhzKGh2+bsei2Tau+89M1Soa+zXNGr1ucU93mpOQFo243I1gAusECYB84JLNQeKTFYgEYMLyxcmBZ43NJeYF/ue9k5769rl7AI8fN0fU8rOw6fdz5w4IJ654vn7bxpqyRzbNLxm0YXTVz3TVF41vuHFQS/mVyTuB3qQXBN/sX6qey1f/poN/oJ7Wo3pmw8FZn0QW7Xyye0PaNimmbzi2ZuGFuRmXjBFUAxqgCUHHa8ntK1OI/4rq1P/vymZ+//8bRs3eEx8/f9pgqAD9XC/tTKQWhX6rLfrFffvClpJzgy3HZgZcHlYb+MaQ8/MGAkgann3r0q0uGfsMf93ofWJz19Y/M3MMMeu7+2XUx75gfJLKwR3Sdq4W/85UFbgnopM9J0M9s1DtJuQGnX0HAGVgaVhr+pfb7y/FqexNzAi+nqO1PyQv9NjU//OuhZU1PqQLwC1UA7lEFoPXEs9q/f33dL6+9qfG5CeeufDBj7OytJQML60tUAahSBWCcKgCVqgAMn37ybSVq8c9X3Lc31gXAX73OSeYzAN0C2yqOBcA+cEhmofBIi7UCoB71zojLqGmJy6r9v8h1UIuXPnHMPYlM039XOo/Xdv67exKf+tNd2NTMfcSsvlb/r2jSBqdq9rbfJuaFrlt0wZ010xe11x5f0rI2JT+wemBR/cMDCgN/TMkLq8VP/399Ul7QyRvX5gwqbdimFsVrVQG4dkBp/bVzz77j2s9/5ZHPz1x0a+UlV92f/rlVPzpxyfn33pBZ2nBDSvbqG3wZN9+QnFN7c+WMzU8WTtz4wvGVLX/Iqm55d2hl80f9ixvcj/KNPhs+8rW+XtHzT9F1IYf/t/Przr8j6t8OugxEXy7ark++J8EfcFILQs5x5Q0fH1fR9I/jK5te849u+c3oE299NqNq/fr4jPobEtNvuaGgquGGs1bsuuG61T9ZoSSg271gbNvi/LFtjipJn9y25rAAdIMFwD5wSGah8EiLhQIwaf6t8aNnb00eVNJYlZBV2xR5c5vOxUf9Qo66TgdT/+6eeKYWDvckM/VoOD3gJGQF3k7Orfvf+JyaX5xw2s5nz//CA9sHFjecsPiiu66tmLL5p2l5DeqRdq1a7Oud/oXhd1IKGv8cnxX6pSoATw4ubXhy6uIdT5647I6Fi87fdXz5jI1ZJ51118TCseun+zLrpsf5lay66ZMXtjfNOGWnc1xxyEnKWqMena92n7aPPDrvWEzgNvcFIffQRULGGiezMuTMXnqbc97l9/06JT88S+2n6VmjmqZPWLBzesnk1ukDiwLTjysNf81fxfcBOBywreJYAOwDh2QWCo+0GCkAKWNmb81RBeCR5Ly69+Iy9VvwqgKgF9HDFYADj4h1YVCLb3aNe4b5kOFNL1VMaw3njmnMza1unTaktLEmyR/cn+APvhufrY/j16oCsNbJHNXqlE3f+lrVgu0bS2duqVAlov+A4nD/6afe1n/VN348/ZQLdi1VBWClKgCvqgKwXxWA/aoA7Fc/e7+6jPf0WwHH+zte0uc+66C2xX1qXW9fHywAHbeH3heR/aH+zNbPFgSV8IdxmYH9qgDszxrZtF8VgP2qAOxXBWB/XHrNO/H+qMsyhwWgGywA9oFDMguFR1osFIDBxU2TlPvV4v+GTz9F7i4eHce1j2QR1QuNetSdnBt4M7uq5afHVzR/s3h86/dGTGndPagkuCs5t+7HCf7a3+vXsuvPyc8e1fLb4ZM3bJ6+ePvqMXO3XVo+c9uCKUtvn37+ZY9cNnHBbdcPq2wKDilpuHNIacPj/QtDv0jJCz2bPqLlnf4F+lFtXeSzANzj6nqh1+/Cp7ahY+GLfK3nnSWgD3L3hd4/+tG8vv260HN12/bLCzhDy1qcgUVhJ8kfeQmlT5/LcNBhB2NYALrBAmAfOCSzUHik2VwArm/YO2/E3NvPSc4NNaTmhdUj945FM0O/VK/LQqC/1sWgk14kOr7Wj+RT1SKiFumfZlQ275i9eOevCsa2rD6+LLguo7zh9yn5gff91c1O/riWP8RnrWnJHNnYUjF1w1dPPW/X+auueSAwfvbmr6uFZ2VqXv1VI2dsfTBnzLoX0opDf0otCH6c4O9YsDoXMnfb1M/U78nvLnKd9KEHpev3aXrb3e2NiLxJjv6eju9Ts4TcgPvStzR1HYaUNTrDRjQ7WVXNjn90k/uqgMpZW5wRs7c6o+ZscyYvus2ZuXRnt2Ysvd2Zcfod6s87ncmn7HRGzdrsjFT/v1RdVu64Vsc/ps0ZNrLZOa6iyRlc3uTocxPcN1hyt7lj/7vbq7evU8e/RS/O7v/pvE5dv19x9xv4e8d5Fu4JjZpb9nQB0B+j3HH5hx6Tl8YC0A0WAPvAIZmFwiPN5gLwjdrftVfMbn/Jpx8BdlkUD6IXnnT1yFCXA/0UsT4ZUL9/vvq6f1FQLZaNTun0TU7x1E03TD3ptosWnb3LyRjR+G5ybv3+/gXhN9Wi+99TF+3404WX39c+59zdBcNGNhQk+GsKJs/bvOT0c3f+PV+VA/3IM149ko8869C5yHX+qbZJL1oHFjC9TXquy4datPRLA3PCTkJ2wwe+rIZ3fFmh/Uk5wf39CsL7VTH5hy9Hv5Vv7WvxmXV7fZmBvXGZwb1xWSElsFfN96YWhvYOLW/am1PVtrdi2ua9E07avnfG4u17556+de+Fq+7fe9k3f7z33659dO+q657Yu6bxl3vbtv7np2pVmrc+v7d5+wt7G7f9197Vjc/uXfXNR/Ze+e3H917wxT17F5zbvnf2GbfvHT9/+94Rs7bsLZuxda9/9Ia9aUUNe9Wj8r1xw5R0JaNObafe1nqXL6tuX1JO/euqJL2l96svu25/fFbd/sTs+vf1ZyUk5ITUvui4/Tr3kz4PQpcld9/pr/XCr8/TiJys6b4XgztX+7nzGZXOBbjztjeHBaAbLAD2gUMyC4VHms0F4IzL97TnjNvwkv5wn0gBiN5+vdgr+v311eLsLtL6aWK1sAwobnTmnX2Xs7r5GeeKax91xs7b8deU7PC+wcMbnUGFjb8dP7f9vsu/8WRd+fStE2acuvP0+efvDsw+Z/fvVAH4nSoAv0vIrnttUFH4w6Qcddnuy+j0QqS/1j9T/7xIKXFfdtg5cxc3vaDp9wQIq0ftTc6wylYnf+w6J2d02/9kVjY/lVEWvn/MCevvX3rR3fdfevVjLVNP2T4jvbJxpFrsylQBKFMFoEwVACVQpgpAmSoAZaoAlKkCUFY5fXOZKgBlqgCUzTl9S5kqAGWXfevHZaoAlKkCUKYKQJla6D+VKgBlqgCUqQJQpgpA2erG58q+9M1HylQBKDv/yj1lqgCUqQJQpgpAmSoAZeUzt5apAlA2oKihTO3fMlUAylQBUF/Xqe3U21rvGj3n1qnnXf7QqlMv2r114olb7s8sC9w/qKDu/vwxrfuKJm5w0ke2qtsjrPaJ3jd6H3WekKkKgFsC9P7V+1T/m/qz81kB/feOQhApD3of6383jgWgGywA9oFDMguFR5rNBWDxit3tWaM3vOSexd/5cbsHbX/noqDfv18vFnXuMfwTz9rlLFm+2zntc/c4iy68x5l0yg4nb9y6p1Lzws3+setunHPq7c0Ll+3eMn3JnVuHVgTDA0vCtw0b0fxr/RR4aoFe1DsX9Kinvjvop+qTsoPOcaVhJ290y1slkza8kFYQ2jGktHGDf3Rba+GkjXWDSpu/PrCkeVXmqLZVJZPWryqasO7ivOqWM3JHhBfOWLhp4ReuemjhTbXPTlu/5Vdpt93+Sx+6/rFidcPzqUrpyq/+6IR5S3cszBsRWHhccd3C0knrLi6ftmlVdnXbqkGlDatUCfpu2ZRNDUXjN2zQ+yq7qvWBUbO2/il/bNt7Q1QxS8rR+1uVAffZlc59rhd/FoAjBbZVHAuAfeCQzELhkWZ3AbhHFYCNHQVgjfrlH1UA3EfbamHIWuO+QU7e2PXOjCW3Oededrdz3hX3OvPOvvPv/up1v+lXEHw4q7q1rWrutuvLp26+fMGyH7aOnrv9oQHFauXKr3830R95FOrLuMUtEZHL1D8joB7FNziDhze+kVbS8HNfTuBBtRDd58uuv69fbvC+vKrG+ybM3bxt4bIffi+/et2CCSdunXHRqvsmrW19ulLpj65TX7Zh228yAk1Pj/nS1+6dPmHephkzT7v9wrMu3dM4cf6td+WOXndf//zwfep2uE+VgPtSCoKPHVfR9NvjKxvfPVDKdAnoevubwwLQDRYA+8AhmYXCI83+ArDhJfdNfNQif+C4e+eJcx1PDfv8Nc5g9Wh8xdX3O7eEf6Iemd/kpOTVOIUT1z91zXcfu3LlVx/MWLLigbqpS+5w3+o2LqtBUZeZsVb9XV92zcfxWas/Ssio+ciXEfogPjPwgZp9EOev+aBs5uYPTjx394PX1z4zSxmAtpOOvTXbXin58pqn/m3Oudv/mDMu/IEva626TYJK/Qdx2fUfKh91+Ng9L6DzPtFx8mekLHSK+rt7HkGXr48eC0A3WADsA4dkFgqPtNgoAPqRvn6aX2+zXsD117WOLyvkZFdvcOYtu9OZPH+HM+vU252zL73P+fr3f+J85+YnnYu/9OBb5dM3/y6lIPDEgNLwfw8ua3Df8z4hM6jfCMjRx/eHVTQ7g4tDv8+panp87qm3P1w4duPFqgDMVQVgrioAc1UBmKsKwBi1+A9R4LvU0bGnCkDql1c/lasKwIzcceG5qgCo2ySo1M8dM2/7tVMWtT8+oDj4+ODyxj8PHN6oFuWO+4Y+CVTdr/VLMX3qdo6cZKhnauF2zz/QC7gufZr6N7zAHw4LQDdYAOwDh2QWCo+0mCkA+k181C9zffw9wV/rpOaHHP/oDc6oObc6c86401mx6iHnjBX3OHPPusM55/I9zvlX7HFmntbuDB6u39Gv3kktDDnDKpv3541p/a+MytZHBhY1bkrJC6zOqW5bnVHeuKpy8oYLvvClR85V0tG2kD0u++qjI5Z9fs8FQ8vDF2SMavnm0Mrm1T5/3dqBJeH2rKqmn/lHN/1xcEnoo2R/KFIA3PMJ1MLdSd2fIsVAf41zcRgsAN1gAbAPHJJZKDzSYqoAqEdtSXkhZ2CJWszLW5yZp9/hzDl7l1M4boPzb9/8kXPJVx50Ji/a5vQrqFHfo8/CD/2/+Ky1z8VlBJ5Lr2x7rnr2rT8+5cJdaxcuv++8BZ97pAz9TIpNC8++K1GZdOqFd6yae8a2LfkTG5/pXxh6Tj3yfy4+p+6FgcVN7+hPEnQ/RVEt/L50/SmKkWcLeoAFoBssAPaBQzILhUdaLBUA/ZK7jKomZ8TsDU5eVYtz8aoHnEuuftDJGtHsDCltcdIKm51+uWEnObPGmb6w3Vl6wX3bVAHIVAUgM6NyXWbVrO3pqgAMXrh8T6oqAO6nzJF3qAKQrArAgHlnbj9OFYCM1IJQpioAmaNmbh17yrK7f1c6oc1JcA8lNThx6focED4D0BtYAOwDh2QWCo80mwvA6Rftac+p7ngfgOw65/jKZmf4tA3OmBM3OcUT1znjTtrqVM/Z8rchJaFfj5yx9emSCZvDvozg8qSMmuWzF9+xfPllj0xFl0t9y1nL9/RXTquYvH65KgDL4zIbl1dO3nxHXnXrr5Jz63+Xkhd6T39yYeQ8AX1oQGXjIHqu89LxfgWZLADdYQGwDxySWSg80mwuAGdedF97bvX6l/RL/NKKG52cMev0gu9MX3Lr/pGzN/8iq7p5d//CQLh/Qf1XFp9311UrrnxwErocomgXXnLPaZPmbflyWmH9dWmFDZvTihoeGFrR/GLuuA2O/kwHn86H+y6EHfSJhPo9Cty/swB0hwXAPnBIZqHwSLO5ACy75O72oonrXho0vOHd3HEb38gc2fLGmLlb3zjt4nueXXLxPRcpeej/ER2tJRftGr30kru/t/Tz976RP7r1jRR/4A1fRv3fk3NrPtKfCqkX//is+o/Uo/83lS+hy7AByrg0FgD7wCGZhcIjzeYCcO13H2i/9It7Xjrrc/c8kTd+0zhVAMaNmbN1nCoAo9Tif7ySjP4f0dFSBaC/KgA5Sy+9d1xedcs4VQDGlYxvvnDmyRv+kVHR6CRl1TsDcmv+X7K/9lxVADLRZdgAZVwaC4B94JDMQuGRZnMBuPnmh077+nd+dPlVX3/0bPTvRL1pybKt2cqXc0c1fyslq/5bQ/JrrlIy0PfaAmVcGguAfeCQzELhkWZzASCio4MyLo0FwD5wSGah8EhjASDyDpRxaSwA9oFDMguFRxoLAJF3oIxLYwGwDxySWSg80lgAiLwDZVwaC4B94JDMQuGRxgJA5B0o49JYAOwDh2QWCo80FgAi70AZl8YCYB84JLNQeKSxABB5B8q4NBYA+8AhmYXCI40FgMg7UMalsQDYBw7JLBQeaSwARN6BMi6NBcA+cEhmofBIYwEg8g6UcWksAPaBQzILhUcaCwCRd6CMS2MBsA8cklkoPNJYAIi8A2VcGguAfeCQzELhkcYCQOQdKOPSWADsA4dkFgqPNBYAIu9AGZfGAmAfOCSzUHiksQAQeQfKuDQWAPvAIZmFwiONBYDIO1DGpbEA2AcOySwUHmksAETegTIujQXAPnBIZqHwSGMBIPIOlHFpLAD2gUMyC4VHGgsAkXegjEtjAbAPHJJZKDzSWACIvANlXBoLgH3gkMxC4ZHGAkDkHSjj0lgA7AOHZBYKjzQWACLvQBmXxgJgHzgks1B4pLEAEHkHyrg0FgD7wCGZhcIjjQWAyDtQxqWxANgHDsksFB5pLABE3oEyLo0FwD5wSGah8EhjASDyDpRxaSwA9oFDMguFRxoLAJF3oIxLYwGwDxySWSg80lgAiLwDZVwaC4B94JDMQuGRxgJA5B0o49JYAOwDh2QWCo80FgAi70AZl8YCYB84JLNQeKSxABB5B8q4NBYA+8AhmYXCI40FgMg7UMalsQDYBw7JLBQeaSwARN6BMi6NBcA+cEhmofBIYwEg8g6UcWksAPaBQzILhUcaCwCRd6CMS2MBsA8cklkoPNJYAIi8A2VcGguAfeCQzELhkcYCQOQdKOPSWADsA4dkFgqPNBYAIu9AGZfGAmAfOCSzUHiksQAQeQfKuDQWAPvAIZmFwiONBYDIO1DGpbEA2AcOySwUHmksAETegTIujQXAPnBIZqHwSGMBIPIOlHFpLAD2gUMyC4VHGgsAkXegjEtjAbAPHJJZKDzSWACIvANlXBoLgH3gkMxC4ZHGAkDkHSjj0lgA7AOHZBYKjzQWACLvQBmXxgJgHzgks1B4pLEAEHkHyrg0FgD7wCGZhcIjjQWAyDtQxqWxANgHDsksFB5pLABE3oEyLo0FwD5wSGah8EhjASDyDpRxaSwA9oFDMguFRxoLAJF3oIxLYwGwDxySWSg80lgAiLwDZVwaC4B94JDMQuGRxgJA5B0o49JYAOwDh2QWCo80FgAi70AZl8YCYB84JLNQeKSxABB5B8q4NBYA+8AhmYXCI40FgMg7UMalsQDYBw7JLBQeaSwARN6BMi6NBcA+cEhmofBIYwEg8g6UcWksAPaBQzILhUcaCwCRd6CMS2MBsA8cklkoPNJYAIi8A2VcGguAfeCQzELhkcYCQOQdKOPSWADsA4dkFgqPNBYAIu9AGZfGAmAfOCSzUHiksQAQeQfKuDQWAPvAIZmFwiONBYDIO1DGpbEA2AcOySwUHmksAETegTIujQXAPnBIZqHwSGMBIPIOlHFpLAD2gUMyC4VHGgsAkXegjEtjAbAPHJJZKDzSWACIvANlXBoLgH3gkMxC4ZHGAkDkHSjj0lgA7AOHZBYKjzQWACLvQBmXxgJgHzgks1B4pLEAEHkHyrg0FgD7wCGZhcIjjQWAyDtQxqWxANgHDsksFB5pLABE3oEyLo0FwD5wSGah8EhjASDyDpRxaSwA9oFDMguFRxoLAJF3oIxLYwGwDxySWSg80lgAiLwDZVwaC4B94JDMQuGRxgJA5B0o49JYAOwDh2QWCo80FgAi70AZl8YCYB84JLNQeKSxABB5B8q4NBYA+8AhmYXCI40FgMg7UMalsQDYBw7JLBQeaSwARN6BMi6NBcA+cEhmofBIYwEg8g6UcWksAPaBQzILhUcaCwCRd6CMS2MBsA8cklkoPNJYAIi8A2VcGguAfeCQzELhkcYCQOQdKOPSWADsA4dkFgqPNBYAIu9AGZfGAmAfOCSzUHiksQAQeQfKuDQWAPvAIZmFwiONBYDIO1DGpbEA2AcOySwUHmksAETegTIujQXAPnBIZqHwSGMBIPIOlHFpLAD2gUMyC4VHGgsAkXegjEtjAbAPHJJZKDzSWACIvANlXBoLgH3gkMxC4ZHGAkDkHSjj0lgA7AOHZBYKjzQWACLvQBmXxgJgHzgks1B4pLEAEHkHyrg0FgD7wCGZhcIjjQWAyDtQxqWxANgHDsksFB5pLABE3oEyLo0FwD5wSGah8EhjASDyDpRxaSwA9oFDMguFRxoLAJF3oIxLYwGwDxySWSg80lgAiLwDZVwaC4B94JDMQuGRxgJA5B0o49JYAOwDh2QWCo80FgAi70AZl8YCYB84JLNQeKSxABB5B8q4NBYA+8AhmYXCI40FgMg7UMalsQDYBw7JLBQeaSwARN6BMi6NBcA+cEhmofBIYwEg8g6UcWksAPaBQzILhUcaCwCRd6CMS2MBsA8cklkoPNJYAIi8A2VcGguAfeCQzELhkcYCQOQdKOPSWADsA4dkFgqPNBYAIu9AGZfGAmAfOCSzUHiksQAQeQfKuDQWAPvAIZmFwiONBYDIO1DGpbEA2AcOySwUHmksAETegTIujQXAPnBIZqHwSGMBIPIOlHFpLAD2gUMyC4VHGgsAkXegjEtjAbAPHJJZKDzSWACIvANlXBoLgH3gkMxC4ZHGAkDkHSjj0lgA7AOHZBYKjzQWACLvQBmXxgJgHzgks1B4pLEAEHkHyrg0FgD7wCGZhcIjjQWAyDtQxqWxANgHDsksFB5pLABE3oEyLo0FwD5wSGah8EhjASDyDpRxaSwA9oFDMguFRxoLAJF3oIxLYwGwDxySWSg80lgAiLwDZVwaC4B94JDMQuGRxgJA5B0o49JYAOwDh2QWCo80FgAi70AZl8YCYB84JLNQeIiIYhkLgH3gkMxC4SEiimUsAPaBQzILhYeIKJaxANgHDsksFB4ioljGAmAfOCSzUHiIiGIZC4B94JDMQuEhIoplLAD2gUMyC4WHiCiWsQDYBw7JLBQeIqJYxgJgHzgks1B4iIhiGQuAfeCQzELhISKKZSwA9oFDMguFh4golrEA2AcOySwUHiKiWMYCYB84JLNQeIg+q6efftrZt2+fuovh+52mf0m/+OKL8P8TfRYsAPaBQzILhYeoJ5555hnn7bffVncrfF87HP2pkOhyiY4WC4B94JDMQuEhOhr6UXz0/eqz0L+80c8hOlIsAPaBQzILhYfoSOin+aPvT8fSn/70J/hziQ6HBcA+cEhmofAQHc7hju8fK++//z78+UTdYQGwDxySWSg8RN0x8csVbQfRp2EBsA8cklkoPESf5rOc5PdZoe0hQlgA7AOHZBYKDxFiwy9VtF1E0VgA7AOHZBYKD1E0fUJe9H3HBJ4TQEeCBcA+cEhmofAQdfX888+ruwq+/5igD0Og7STqxAJgHzgks1B4iLqKvs/YQL8EEW0rkcYCYB84JLNQeIg6Sb3cryfQ9hJpLAD2gUMyC4WHqFP0/cUm/BwB+jQsAPaBQzILhYdI0+/NH31/sQ3abiIWAPvAIZmFwkOkRd9XbIS2m4gFwD5wSGah8BBp0fcVG73++utw26lvYwGwDxySWSg8RC+99JK6e+D7jG3Q9lPfxgJgHzgks1B4iPQb7kTfV2yFtp/6NhYA+8AhmYXCQxR9P7EZ2n7q21gA7AOHZBYKD1H0/cRmzzzzDLwO1HexANgHDsksFB6i6PuJzfTLFdF1oL6LBcA+cEhmofAQRd9PbMZXAlA0FgD7wCGZhcJDFH0/sZn+pEJ0HajvYgGwDxySWSg8RNH3E5vplyyi60B9FwuAfeCQzELhIYq+n9iMJwFSNBYA+8AhmYXCQxR9P7EZ2n7q21gA7AOHZBYKD9Hbb7+t7h74PmMbtP3Ut7EA2AcOySwUHiL9tHr0fcVWaPupb2MBsA8cklkoPERa9H3FRnwPAEJYAOwDh2QWCg+RFgufB4C2m4gFwD5wSGah8BBpzz//vLqL4PuNDXRBQdtNxAJgHzgks1B4iDpF319sgraXSGMBsA8cklkoPESdbD0ZkI/+qTssAPaBQzILhYeoKxvPBUDbSdSJBcA+cEhmofAQRYu+35jE9/6nw2EBsA8cklkoPETRbDkhUL9BEdo+oq5YAOwDh2QWCg8Rsm/fPnWXwfcjCTzuT0eKBcA+cEhmofAQfRr92fvR9yEpaHuIEBYA+8AhmYXCQ9Qd/e570fej3sSn/elosQDYBw7JLBQeosN5+umn1d0H36eOJf2MA/r5RN1hAbAPHJJZKDxER6q3ftHyeD99Fja+dLWvg0MyC4WH6Ggdy48P1q84QD+D6EhF36fIPDgks1B4iHqqp68U0M8k6MMK6DKJjlb0/YvMg0Myi4+2qLe8+OKL7gmD+o17ut7n/vnPf7pzfpQv9Zau9zeyAxySWTzWSkReYvr9KgiDQzIPhYiIKBZF/34jO8Ahmcf3ViciL9CHnaJ/v5Ed4JDsgMJERBRLon+vkT3gkOzAd1sjolhm8m2q6fDgkOzBQwFEFIv41L/94JDs8tJLL8GAERHZKvr3GNkHDsk+LAFEFAueeeYZ9SsL/x4ju8Ah2Um/lhYFjojIBvqBSvTvLbIXHJK9+CZBRGSjY/nZEyQDDsl+ugjwLYOJyCT9dD8X/tgFh0RERORlTtz/ByjTnPQ/HMIyAAAAAElFTkSuQmCCDynamics CRM Mobile ClientGE.EIRectanglefalseAnyAnyfalseA representation of Dynamics CRM Outlook ClientfalseSE.EI.TMCore.DynamicsCRMOutlookClientLower right of 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Dynamics CRM Outlook ClientGE.EIRectanglefalseAnyAnyfalsefalseSelectGenericCSharpNodeJSIoT Device TechnologiesVirtualDynamic0e4c07fd-732f-44e3-901a-81446a6bcd4cListfalseSelectYesNoIP CapableVirtualDynamic5a86ce50-eedb-4cd4-9686-8619c3196d05ListfalseSelectWindows IoT CoreOtherDevice OSVirtualDynamicc654e773-cfea-4cee-b832-ed22bf619348ListfalseSelectDirect connectivityAgentsAzure IoT device SDKsDevice ConnectivityVirtualDynamic2774528e-4318-498b-9228-8341d7112a6aListfalseSelectAzure IoT HubCustomDevice Identity StoreVirtualDynamic51551b3e-c1e1-4181-b8d3-b74ad078b0beListAn IoT client agent which generates and sends telemetry data to the cloud, and receives messages from the cloudfalseSE.EI.TMCore.IoTdeviceLower right of stenciliVBORw0KGgoAAAANSUhEUgAAAQMAAAEDCAYAAAAx0WHLAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAOwwAADsMBx2+oZAAAABl0RVh0U29mdHdhcmUAcGFpbnQubmV0IDQuMC4xMzQDW3oAACpZSURBVHhe7Z35nxbVsfCHXUQWgSCbCiIuCO7exHwSF3KjbzS5r4mJMTG5Nzd6XaNxlmcZZhhmBgaGYVUQjeQqxHiVRUUkoqJhGWD2AWRREFDgvn9HvVWn+xmHpobZus/SXT98xamZ5+nTp05XV9U5p04eAHSJpzYcg7tf2g9T5jZAn+d3QF7+TsijfwW7KaiFvHQTPI36C+pUJyNK6rAtu/k2CuGCz+bkufUwc9V+oOc2qIuOYIU5Hlt3DCZUNuJgQlINkFe4xxtcXAME+yBdod7+/K5ZQzBs1l4cOwjXRiEa8lH39LzSc4vP7/iKBqDnOaib9rDCOVu/geGkwEwT5BWhRX9evADnoLcwDoTn3zuOKj1Xx7oYXlKPYwjh2ihoAp9feo7xeabnunzr16iac3V1juBnfz2EH2oWS+4ybR7BV6jSs/WrkyEZejOJIbAKeq4xbHzkjS9RRWfr66wf7n3lc8jLtqKLsYv/IsF+lEdQD/k2eARiCOykAJ9vfM4feeMLVNW3Omv7H0owKY9ADIG7+KFBwSazhmBIFj0CFV4ybRTsQCWWG2H+tlOoMk9vbQpUA0myve7iewSmDcEwlSMQQ+AEGDIMSdei2jzdqf/8hMIDjCPYDwj20+YRmM0RXFSM8agYAofYqaKB36w9jOrzjcFgtA55BejasR8QrEYlC+uh0LBHMHQWGgHJEbgHegdDMawjHSpFqlwB94eC3fihQdH7J5QyTaEMgXgE7pJuRjWiHfjVmsM4oESRztFmCEwnCyk0EI/AadCQ/2z1Qci7bWmrN7C4PxLsxM8RWBEaiCFwn/xdMKkS9TimFC27TCe6g+8RFL5nNll4oSwoihV9aa9RH1lq7A6FaAjwTZzabNojQCMgoWXMQDvA/0KwDt8jSBnOEVyocgRiCGIJKxTswjcEmQ/MzhoMl+nDeMMKBXvwDUHacGgwajYaAUkWxhtWKNgB7UlPN8IzG80mC0fQdvZUA99GIT6wQsE8/kaSJ9ebLUwyqpSShWIIEgErFMyiDEEDPLH+KD6P/EOqA/EIEgYrFMxhi0cwG42AJAuTBSsUzKA2HTUYNwQXU/FSMQTJgxUK+lGGoBGe2mA2NBgpOYLkwgoFvfg5gqcNzxqIR5BwWKGgDz9H8PRGs6GBlywUQ5BoWKGgB0s8gpG0oEgMgcAKhejxk4V/esesRzCsWHYfCj6sUIiWnCEwHBpcrJKFYggEH1YoRIclhkB5BLLXQGgPKxSiwc8RPGv4pCPxCAQWVihA6KdMt+UIzBoCdYZmkg2B0qsU9GFhhUmByr3R2XO0yCbTAnnF+zyy+P9UwIP+zf1Mh9DS39HJtt01FH7NwucMewSJqUfQkV7p/0mvVA28va7RW8srwr8ng819X1JghbEEH2B6kClOpgdCHRqzEybMqYPblrbAz//7EDz69lHkGDyD8fyCbafUlB/9/Ou1h+Gelw/ALUtaYOQsP/tOA4j+pcF1vkHkewTPvWu2HoEyBLHMEZyr1z5orCeWe3p9oJ1eKU9T/elpdQ4l/UzyB18/BN9b1gqXV9RDvwL8rnSj9z1ETwy/y7DCOEFvCXpD4CC5KLMbrpnfCH9869wTaHvCL18/DJdV1EH/QrwGvWHoOu2Ly7YZArMeAR2SoQZ3+35xnXZ6HZrdDdcuaIT/ePPsg0R7Cu0NuaGmGS4u8b0LenG012tcYYVxgKx6Cq08PpC3LdsH5R99g3rmlR8GxVu+hlup7DwVLVVvF/IczBuCEXE7DZn0Sv2bX4v9vQ/mbP0ab5O/9zBY+NlpuGPl59CHrk3XpXAi2Ka4wApdhuJzjA1HlNTBH/7HzKafh9YegUur9sOzhpOFQ+nsw7gYAjKyqFdKgP4+JA+gu1DYOKYM+5NyD2SUuHa6DCt0EXLJ/VDgMYwFg4pMGsPj4hFQ6bdMMwzDUMf01u4c6c0n4Duz0dBSUplePly7XYQVuga55Gipf4ExfFBxSeSiuBx5pvS6Fx54zU69/udbR6FfkTdTFIvpSlboCpTUQW/gmuoW1A2vsKShPALXDQHpFb2BaTWteEv8fdrErcv2+17CeWaVXIAVuoBKENbDr9eaiR9tJBY5Al+vD//NLb0+ueGYZwxcPmCGFdoOumWD07uh5rPTqAdeOUnjIpo+dN0jQCNAel2y/QzeEn+ftjO6FI0BzTpw92c7rNBmsKMnVjZiv/PKSCLfKaNpTMcNAbrZEyub8Hb4e3SJa6oxZKBVjq7lEVihraSb4OoFkh9ozyh6E6kEFtNfrhBDvX7vhf2+h+CQQWCFNoID5rqFzdjPfOcnkTFz0AjQsmiuv1wh3QzTY6rXO1b4+yFcMQis0Cq2Kws7pSoeLmRYjFalylw2BJ5er5gXb73SKkk108D2gWWwQpsoqoNLyiVH0J5Y1CNAvY4pa8Db4e8xTkydj8bABcPNCm2hYLda1BHs3CQzJA6bjlCv/Yv24O3w9xhHaAWl9fsaWKEVYJyVaVbbTYMdm1TiUc4c9ZpugoJNydLr0h1nPN3R8mq2XyyAFdoAxpN3rNiP/ch3btIYHYfpQyLBen1ozWF1/2y/2AArNE3hHhhWvBf7j+/UpDEiV1CF6yuXQL0OySQrPAhCxXSs1SUrNIrnRpb+4yT2Hd+hSWKU87MGOSjsE70SeSk0CDYWS2GFJkGreV21zB4Q19c0exWUuH5yDdTr9IUyPUz86KX92B8Whgus0Bj49iiqw/7iOzFplH140u4Ys8ugXtEYBO8vyfQtrIW8Asu8A1ZoChz4VMQy2HFJZlJlDBKH6Qa4vka8gvZQgV3rFiOxQhNQFVqMjYOdlnTmbzvleQeuVuml2Fi8PZYBqT121UBghSbAATO5UgYNB1Vgpv5h+812sN1T5kqIwHH7cqqobZHXxwpNkG6CwoQtROkqVO/f2dwBtjtpC4y6ygs7z6gQSuVUuL7TDSvUDbpKF2TMryso3nISZq46AFfPb4SrqhrguoVN8CP8+amN5gdzX6oA5Frt/oJdMChtXq9Z1OtPVx+EmxY1w1TU67TqJpj50n54+h3zeh1dgnol3XL9pxtWqJt0M9y1ch/2Dd9hUbJsxxm4eXELDEztxlHTqvIWag25wq8VQHL8edLcBqj4+BR+jP+uKKGBbOV01PlAb+/OFebqGNKBOSpjT/ojz4r0GdRr4V6YPK8RKj8xU12JTuvyCqEw/acbVqgVdJFQUWURH4bB8dNXD3oDAwdtpyWv6a1M8R22dcZi/ctpyWtR7bTFpewU0msTzPlIv17vXHnA0xU98J0l6Nr02gTTF5kxXKqNNnh9rFAn2BF0xl2wg6JmLBUGyaJF7rYScJBnmowsqx1UhG11pU4/6rV/oX69jiO9UkGRbs++eMZrcLoWv4b/7qi4MIXXtkGvrFAnGC+Nna03rqTTlnqdkEvVQf+U3naPnY2xpe3bYHNgO6m9wXuIkiF0XkRvKz+hp9hPs15nVPshDNcenbBCnaCLds8rn2Of8B0VNtdUozfQW0OQo6geRs3WtzbirpX71TXZttgG6vVejXqlIrkqLODa0l2wj0eX6VsS//j6o+G1vTewQp2ga/ZnTTULHnztEIYGIa/1zzTDnSv0JD+L3j8RniGLGnxD6zprcuZL+7yQj2tHT8FQY6ampHbNZ6fsSCKyQp1gpy/fqSeTOzCKmJtyDgX63GF3jEET0ExNsP1RoKbmwk7A0ffh9wavFRXeTFF38xwhwwp1QUkedMmCHRMFj739pRqgbDt6Cxq0H710AC/DXztM+tJUWWcZctNo1Ov3l7di/0el12a452U9oc7gdAQvqu7CCnWBNz9QU8bZS75FlKTBN8ioWXreIkMztNvNkkUqHYHGimY+gm2PgjGl/poQrh29hfRaokev4+egTgsNJ4dZoS6ws0cU65nKUYYgss0++L3odQSvGQXjynDAmB40nYHGalhWp15DDhHag2FZ8JpRMKWqPrqXVVdhhbpAi36JpumnyLeLoktZreHsx6lVGFvaMA11PtBYjUWjFWx7FERe/AWN/NxPol91et1Cmg0xPFPECnWBg/ryiuh3KpZ/9LWy8GwbwgK//5mNx/ByfBvC4qbFzXZMQ50PNPKTKqPPGVTR9u6ojXy6QYteb1lCOxgN65UV6gKNwSQN25YrPv4memOAinzkjSN4Ob4NYXGLE8agDqbMi379hdJr1MYA+/rRt6I/Hv62pbT+JdHGYC+MK9MVJkQ8j4vuZOH70a+XmLEQB79pd7IzMEwYN0dTmKDOMmTaEBZobHQc/T+9JulhQuEeuHiWnhOTIn+DZPVscrmyCt8e1ucMSK8xMPKUcEbDFrxmFFyZ+ARiwW4YXKRnanHM7Aiz8AW1MDCtZ/BPLMd7iGoqLSxoalHTlDG9TMj4sO3oLfi9IzXNdllRzYoV6iJ/F/TRdObevaoAZURvkXQj/IumQq5D0rTOwPKdizTVl6/nIVL7NaLy+vB778bvD14zCoZmaMVjkhcdEVl91ZCVZxD6nDStMWiA6k/1FD3xkodRrZcIEU3rLgjvjRq2XvH7MIZfrmtJNXl7Ua6X6AqsUCc4aDIfnMD+4DspTG6swTdI2LMKqUaYXq1x4EedCA0L7Oc5mgrWTFuABjLsKlBoCHQWcrVCr6xQJ/im+8Vrh7A/+E4Km75kgcNys+l7MK4MXiMqnn3nmOovti22gQ/TI29EPyWXIw/DzdD2bNBJydjPwWtExZ/f+0p5l2xbdMIKdYIP52SNFpjO+iNvpNcGgQYevv10eTXEd5fRwhTLZxJyFNXDvyzVV0bs+XePejmh3rra9PlMCzy+7ih+LX+tsLl9GdXetECvrFAn+FAN0Fwe60kqJkHhQk+z0PQ5NCiPvvUlfh1/jSgYnkUDFFXmPGywnaNL9Ewb5/jVmkOeQeipoafP4ecfev0wfh1/jSgYppKHFuiVFeqELHFRHSz8TG/VYVrKSmW8VSa6q+4luY/491TWvWpb9AtRgvRxYftyDmwntTd4D1FTSAVg6KEmY9/VvqK/U3+/B57XVGinPdbolRXqJtsCVIUo2Ek6uOeVg97g8ctmK+NEi03a8K22//uZqw7ix/jvipI/Ub7AtROZ0d2mdgfvRQc/XHGgnd7w37P06j98NAuhfr8bbl1qplT/UxsovIl4QVxXYYW6QWWN0uxSBnl03VcwsbzeMwxUL4ASjTSI8Gcq2Pq7N/XFkBx0sIv1y5CDpBrgtiXN2Hz+nnTwh7eOwbgyfOhJr6RPMvioX6q3cO2CRnh0nRljleMaNRNiiV5ZoQnQTQt2lEmqP9UfBpwPVQiV3mpc39kKvoEHFOkvPX4+dJVi6yqeN2qJXlmhCdA6/uBFc6fv2MxDaw6jsXRkSjEIGvk/vmXWq7KVh+k0JZv0ygpNkF8LdER1sMMEyBteTO4twvWb7WC4ZToEtBWq8mWVXlmhKbIt8KvXzSQSbeX5d79yL3HYHnKBZ+2Hyo+/wdvh7zGJqISwLYnDHKzQFAW1cGFWvIP2XELJL1e9AgLDBDrYNHhfSWdk8W4vSc31mSlYoUnSTUCLR4Kdl0SUV0CrJV3YmMSBhmBKldnZBBspev+4nyuwTK+s0CToHQzM6FuebDNDZ9W76xWQIRCPgOUi9H6t1CsrNA0OpBtq9G1ttpEfr4qw/kLUoP4mlItB5/g/r0RYf6G3sEIbwAFV8o+T2H98p8YdK/a39wR0fydW6tvS7Rpq1aOtemWFNlC4GwZlkplMpJOd1WIUrl9sJtUI4+aIR9ARo8sw7LMtadgeVmgLqQaYPFffvnIbuHVpK75dLXUjzwd6chMrJEfQEbcuwZDP1vAgByu0CXwwqH5hsHPjyO/eOOIZAteWHaMhGC85gg6h8zSc0CsrtAnqQOzI3/1dX9UcE6jpJqpi5FqeAEODiZXiEXREerNDemWFtkEdiW8fE3vNdUC1HFRiiXbWcfdvK+kGmFCerDCuO1QrvdIuWEf0ygptRO0/3wtULy7Y6S5T9ck3MCDt4CpDNX0ohqAj5m87BX1Te93SKyu0FbKw6Jb++5t6y41FReGmE55HoAbM9nPv11ZQB5fNlenDjsh/j/TqmCEgWKHNqJChCe5b7faSZSqWomJJ10IDNATiEXTM7/FF5aReCVZoO5RUzDTB1AVurnu/cXGrt7rQtWQhhgbiEXTMDYtQp2rWwDG95mCFroCDc0DhLpjlyErFRdtPg6pNQAOGux+bwb6eWCEeAcfif56GYbTfAPuI7TtXYIUuQefToRJuXmy3l6DOBCT30cWVhdi/l4tHwHLHin2gStK5qNcgrNA5aC0CWeWd8Nu/21Vi64kNx9S5EE4sOuHAfr3UsEdAx7Tds9qudSZPbTyuvFK1qtDVsCAIK3QVUkqmBYYU18HDfzM7eB5ffwxGlqInoA71sKAmfk9AQ3CZ4QVFFR99jW/dOq/aE/bjD140U9I8x6NvH4PRtHekN4e12AordB2a0sE3cb+CHXDvX/Sec/Dz14/A4BQaJfJUXHYdKTQwbAioVJoyBOqo8u2eUaV+xYfw5iWtULxF39F2D7x2BC4oIr2iJxCHkICDFcYFNXhQeTiAxs+ph3/7azSG4VdrDuODg28Lqn/vsieQA/vLdGhQ+bHvEdAZFsH2kQdIfZ1thQtStXDLkhYo/Uf4Jz7/eu0R9IxopyG2Iw567QxWGDcoVqdFIJTAI1A2o6YJfvH6YaCTjWv+2bUzEpbuOANUiuwhHCSUsOxH36u+0x8wcYgd0w0waa5Zj6CcQoO2xVhMG9ujFqKhDiiJh58ZXbJXhRJ/fOtLoFWAwe/moLMU8jcdV3q9cVEz9I2jXrsCK4w1qGhSLg0esvbF+5TSaQBQom9ophZGztoDFxfvVv8Oy9bCQHQP+xWQQcGBkcW/p/iVBop6U6CcvY6DoEdwmWGP4FtD0N14nPSKqBARQwk6No0e6IJd0B91RycojfB1SgzP7lZ6pd95esW/z+mVztSMk167CitMGjSI6MGmtwwNpiAkp9/H+Q2BD9DkeWanZz1DQEa2u4agA0ivpLOOdJsEvXYHVigkC8oRGK5H0OYRhGUIhO7DCoXkoDwCswuKyj4UQ2AFrFBIBsoQmE0WziZDkOpJjkAIHVYoxB8LPILZH54MN0cg9A5WKMQbNARXGDcEIScLhd7DCoX4goZgkuGK0+IRWAorFOIJGgLTZx+WSrLQXlihED/STTDZ8MrCUvII1GItMQRWwgqFeIGGYEqV2RwBHZUnhsByWKEQHyzIEZT8gwqEiiGwHlYoxAOVIzDrEdBmIc8Q7OHbKNgDKxTchwyB4QVFCz87jYbA3wPAtVGwC1YouA0agivnm501qP4UPQIqAkIbgrg2CvbBCgV3STfB1PlmQ4PqT8kjEEPgHKxQcBMLQoMF277xDYGEBs7BCgX3QENwleHQgM6N7FlhEsEKWKHgFpQjsGHWQHIEbsMKBXcgj8DwMXPe9CEaApk+dBtWKLhBpgk9ArM5AvEIYgQrFOzHAo+gLUcgHkE8YIWC3aSb4GrThkCFBrL7MFawQsFe0COYajg0mEcnHcmsQfxghYKdoCEwffbhPJk+jC+sULAPNAR0RFzw4dSJOvtQVhbGF1Yo2EXKvEfQdsCJeATxhRUK9oAewaWVZusRVHyUmzUQQxBrWKFgB8oQmPUIKsgjoHMNZPow/rBCwTyULDRcs1A8goTBCgWzkEdg+DTkNo9AcgTJgRUK5kBDMMn0achb0SMQQ5A8WKFgBjQEEw2fhuyFBjJrkEhYoaAfNASXzzW7Dblt+lByBMmEFQp6sSBHUC7JQoEVCvpQOQKzHkGZOhZdPILEwwoFPZAhMDx92HYasuQIBFYoRI/KEZg2BHTkWYN4BIIHKxSiJd0EVxg+DbnNIxBDIORghUJ0kEdgeK9BqToEVTwCIQArFKIBDcEUw+XMSyVZKHQEK0wi+TuRXR4Ftd7DQv/mZNxnugOGBqY9AnUactI8gs70Sr/nPpdEWGHswQFAA4JiZnxI84r3qbd2rspvv4KdMLBoF/TJx7+lYh40/55t9aCHiYp7KAPRxYGE332F4XMNShIRGnB6xX/b6XVA4U7oj/+q2RPSLemd/i7T3M5jSqiBYIVxhAYJKdtnED7s0xc2wY9f3g+PrTsKlR+fwmfm3IfohZ3/C8t2nIH05hPwh//5Er6/vBXGzsZBRINGfRc+YGQslHFgrouDbbLhWQMVGsQ1WRjQ6wB80K+rboR7XzkA/7XuGNBiqmB/5CDdUhm3J9Yfg5+uPgjX1zTDkPTZ36e+n7tuHGGFsYHeAPgWz7Yod5AKiT689giOA35wdJfqz07Dv646AOPLyVtAA0FvFzV4/DcLeQSGFxTN2hJDj4Bc+za97oKr5jeFqlfiP978AqahUelfiPokj5D0G/eQghW6DinNt+yXlO2FP759DPXLKz1Mfrn2SxicQg+BHj50PacYDg1mbaFkYYwMQZteG+CS2XXwn2/p0evTG7+CyyrwuuQBUn925AW6Dit0lXaDZdqCJli28/+hLnkFR0lq80m4c+UB/F/+9zoo3hKnZOG3er22ugmW7DCjV+Lmxej9tRmFmHkKrNBFyG1Et3zaQrNTdzaQ/SBGhkDptQmm17TgrfH3a4LvLt/vGSgyDFy7XYQVugS5bDhYhpfUAyXKgkpLGrExBG16bYDSrR0nAU2yeMcZGFveqNoZi9CBFboCDXhUxL2vHkLd8ApLEpk2Q+B4Bpym/VCvP1kdblIwKh5cc8TzEijJyN2PK7BCF8DOH5jZa+1bQzffGgLHPQLSa3ovzHZMr0u2n4Fh6J2qdQvcfbkAK7QdfGtMrDBbHswm0puPx8MQKL2aXaXZWyhnRUflO7lwiRVaC3ZwphluWGRXMskkmQ9y6whcDg1Iry0wIybJ3x+uaFXj1Lk8Aiu0Ehww+Oa4a9VB7G9eCUlDLTEmt9Rpj8DT6x0vfY63xN+nizzw2mG8LzTSLhkEVmgd9OZAQ7ByP/Yz3/lJY94np7yEleuhQbYF9boPb4m/T5d5aC0aBAoZXFmPwAptA98cEhp8S9U2NATOn4a8Xen1xsWteEv8fcaBmasOeCED2weWwQptAuNh0+XBbGIuHYuuPAKXDQGSqjd+srQurscXmROzDKzQFvDNNyi9G/uT7+SkoY48I4/A9dAA9TowtQdvib/PODKyBPVm+2pFVmgDlHhJNQI9AMGOTSKxOQRVrSxshPKtJ/G2+HuNK55HZ/GsDyu0ARww978qMweEZwgoR+C4ISBQrz9bnUy9Pr7uqB8uWJpQZIWmwYE/siRZbmRHtHkEcTAEqNfRpXvxtvh7TQJXzqPdlwjXP6ZhhSahaRi0npQxD3Zk0lDrCOKQIyBIr5kmmC96zetDOrVx/QErNEmqAW5aJNuQiduX00q2Fr6fXAP1essS0Stx3ysH/HCB6SeTsEJTkLUsTLYbGUR5BS6tYmNBrwBDneC9JZn+RbXo8VmmV1ZoCnQj6W0Y7Lgkc/dKqtxLG1+Y/nIFfAtShaDgvSWZ+1/93D69skITqKlE2YnI0a9oj91TUueD9IoxcvCeBMgbmLZMr6zQBOhGTp3n9vbVqPjesmZ7M9CdkaqDq6rEyHP88EU6h8MivbJCE6SbILsleQtRusLi7WfsTDh1BWw3nTkRvCfBw9OrJesOWKFu0FW6IGN2XcHCz07DzJcPwrAsJXZ2e6CSRpfsgZmrPgfaJRj8jE6GFVu+eo0D2zsobTZEmLftlNLfmFLsP79NpNcxpXvgvtWHznvIig5GleA4o6nGYN+ZgBXqJtME5DIFO0oH+ZtOwISKBu/Ni95JW/Y+h6rHh7/LtMCIknp4bN1X+DH+u6LESzg5svstB9UpeNHM9uQnNhyHi0vRBaepWdIf7fA8S6/4M+k72wKjZjfAHzSdrRHkoTWH7NErK9SJv8iIavgFOypqbl6CMRsNFDp6rNM95/h7GkBouL4zx8xuO/UGoYHMts8y1CKjZsh+oD/0I/2oTD3pqysuOO0ZwLZOrDRz6E2boeLaphNWqBN02/riwAl2UNQMxrBEvRm4NnWGv2GobKveTVRD0v4bjWuTbaBe+xXswmbz9xIFlR9/A30oDCD9cG3qDErm4edpm3jwu6NkcAoNlgpLmTbphBXqBK3y+DK9ceWAFD5Q5A1w7ekq9FDi4Kn5TF8uYfJcDGd6OtB1g17MBM16VX3TW2NJn8fv0alXWnHb6/EYBqxQJ/hA/eQv+naxjatAbyCs6RwcOIMy+lbW/Ww1xpc2TUWdD2znva/oq2s4rIQMZUiJOHxBXZDRZ8geX38U+wvbz7VFJ6xQJxizP/eunqSct5qvFa+7/dx29BQMNa5fqCeHQGGJynFw7bCNdAM8+44evd65gvQachIu06Rtjwx5IVYkEVmhTjL6ahv2obXg+WFPz+F34lsweK2ooIIvfDssA43ksh2nscn8fYSJcu3DTsDR96HrHrxWVHhGvgvJzihhhbqgjLOmDv/N345EZ31pahTfTsFrRkH/Qhykaq6caYctaNTrT6OccsXvvVtTRe4L06hT00lEVqgLHNQDCvTMJIyOcnEHvpmGZfXUahxRjPfR2yRZ1OCgHlioR6/jZqNOo0qqYj9flKnFy/DXDpMJ5XQfEY3PrsIKdYGdPaJYT2erxFunawl6gaZwZ0I5ZcwND5rOKNgDwzUZR5V4i1SvevIGU6gCkumZIlaoC7SEY9GyBzsmbJbtoLX9PVxT0FVw0NDS1+C1w2ZqlQPTi2isxs3RM8tCKwjZNoQFjpsyDUf9T68JcZarp7BCXeCgvqwi+kFD688jz8Lj9z+54Shejm9DWNy0iAaNBdNQ5wON/KTK6PU6/9PTaIQjNvLY10+si16vVAXKuF5ZoS7QGFyuYdDQyjQdxuDRt7/Ey/FtCItbFlswaDoD9Xqlhu3o5InpMAZPro9+34IYA3yDjNO0Si2yjHMO/H4yOsHrhs2MhRa4k52hwgRNeo08TGjUsuz82mp8WSU6TCjcAxfPikmiCQdl8JpRYEWiqTNUYliTXmkZb5R6TevZvEQesnG9skJdFOyGwSk9m1km4Jsqss7GwT9UU/Z8Is0mmJ6C6oyCWrigSNPUYpm3l4BtR2/B8TlE09SimvrGccS2QxesUBdqlZeeoib/96+0b5yWIjPt6C0YItyZpMUpnYFv6j4pPbMJP/lLhIVF0Sv4/gt66mwMKqLFZEledERocq8J1dmhl6dGF1XrcmRKMkXoFoeFpvl5QhWgiUivy3f8L16Cv26YeMvMDeuVFeoErW9q83HsD76TwuSel/fjIA054YTt13noS+TZ87BIN6Je9RSsuX05VTMKuV+w/dMW6NmAVvLhyei8m+7ACnWC1veB/z6EfcJ3VNgML6nH2CykGBNjvAEaa/w9s/EY9pfl04o5UK//hqFZ8B6i4sIs5VLC0yuVpw9eIyruo1DH9EwCwQp1UrRXy8Kj9qjlvL1NwhXsUQqs/lRfEYxb1Vx0RMmysNGs14WoB2UMepuEo1ASvYxyjVWsLsd+siIpzAp1UlAL/Qt2YJ/wHRUFVOlYHUzSU2tMisOBl9YU3uQYlqk1n3HuKvhQ6dqslKMyd2J1Tz0E/7MFm/TqdVDRTs8IcW3SCSvUCnYEKmCBxjdsjvEVjSrR1eUHjP4O/55CjeB36aBPIRqD0OsxRAUl4BqM6HVkKYZSpNeuPmCUgMS/p88FvytqZn/4teonK5LCrFA3qAiKm4IdpYPH1x+HEVRSO+tXSqYHnuoFtIEDhZRVvA+GFNfBb9+IfskxBy11VgOc6z9bwfZSiffgvejgwTVHQB1fVuyfWkR6bK9X0rPSaytQvuFhQ3qlqcvQk589hRXqBhV1UUbPop2OmL/tFNyLBmn8nL0woHCXqthMhUSGZ2vhBy/uh7KtZg/bUIumbN+6HAQfuouy+hKsHIWbT8J3l7cqPQ4oqoU+2K4BRbthbFkd3P3SAaA3c/AzOrnApvMWWaEJ0Dou0LAF2FXUWyzKZbdRgd5W1SdmDamtFG854XmjXL+ZgBWaAF25G2rMHGJhO2p9hIormX6zHdKrpoKxrnFpOXoFPU12RgErNEF+LfTVOLfrEoPTFO92MRlmG6JXlqVUcIdyGTZ5e6zQFJkm+PGqA9hXfAcmkX9/8wv3EodBUK93rTRz5qKteFuWLfP2WKEpaH15gZ5dYq4wWCWYHPUKcuTvgr6Fotf20CnQVuULCFZoklQj3LnCzInMtvHw2kP2TDv1FnwLil7P5pI5GCZIAvE80LZmTdtfbWdghubHLZl26i1qu7roNcj4SjT2thgEVmiaVD1cWmFmlZ8t3KDKm5FXEOJRcKYpIr2KQQhijYfACm0A3ePf/u0I9hXfgXGm6P3j/uBwcF1BZ6BeH3njC7xN/t6TypQq8hAMh4Ss0AbIPdZ41p1N9C1yeCqxM5Re6+CFHWfwVvn7TyqTKxvMGgRWaAtFe2FoNllz1OPn1Kkwie2PuJBAvXaVK+c3mzMIrNAm0F2esSgZc9Tff2GfeVdRF+kGmLZQX8k7l5g8l3IIBsYBK7SNTDPc/oKegqOmuP/Vg+4vLuouCdBrT7m6GseC7lJorNA28hEcODNfiufAUcfFU8LQxY1IvYHuN9MCP35ZVp1yTKcZJfWC0DQuWKGV0MBpgpkvm9kfHxW/XJMzBGFX93UFX6+rDmJ38H2UZK5f3OIbBK7vQoYV2op6kzTBjRqrEUfJj1b5Nf8Tawh8fA/hZhz4wT4S0CDgeNdiEFih7eADdEWV29udb166Hz0CjS6gC6BeKZse7CsB8mYs0uAhsEIXSDXA4GwdVH7iXkGUi6lGX1JmDboL6vXCbD3MdVCvUXPjktZoDQIrdAWqY4fx9v2rD2Nf8R1oE1Q/UR0UakNZbJvx6xPe54hedTKjJsKQgRW6BMWbaBBG4Nu29EM7y2vV/PMMjJ2D3gApMen5ga5C/YTeE1WitlWvpojMQ2CFLkLFQlONML3Grm2yty7d560otKm8lUso768JpmPMHOxbU2Q/OIn/8L/TxfU1EUw7skJnwY6hBw89hWvmN8JSTYdmctyypMUzAFTNJmnrB0LH1ytyNeqVPK1gf+vg+U0nYQKdtZHdB33RSAV/r5ubwvYQWKHr0MOnBk8DjJm9F37/pp5dcv+17ihcRptN/GtLSBAy1J/t9fp3PXr9+etfwBA6Cp/Wg+Q8vKK90D+1B17Yae6FQ9A0e2gGgRXGBjQK5GZm8S2NA2lSZT384rVwDwOl1YNTqxqgH5Vso4NY1NkG4glEy9l6vWJuAzwYsl7vX30QvjMbDQ89/HRyN7eLFHXdB9sx72OzOY3QPARWGEf8rbPqzYIWng5JuXJeA/zgxVb4zRtfQHrzCXVuw6J/nsb+/bajqYrtgk9Pw6wtJ+F3+Ca6a+V+5arSOYLqTUHfR98bl4pErhHQK8muROP8wxf3wW9Rr3QsfDXqryagVzo0h87cfHrjV/DI37+E7y1rgfFl+D30XTm9kmHvzLsjo4TMNWwQbg7DILDCJEBnFuYUr45Wa/J+9k8tImOh/o6Uzf2dPPx2Qg8vpy9/Orcv7XMh3SoZPvDkXbQdrUcPfw+8OksMwk2LySD0Yv0KK0wkOAhoINBgogc9B/2s5D0YJIIFMHqNQqe+Qag07SHQ7FVPPQRWKAhC9/ENQtlWs+c3XoVhUo8MAisUBKFnUKIxVQ9F75/A55J/WHVwDdVDoBCJa2NHsEJBEHoOGYSieijcZNggLEBj0B0PgRUKgtA7KDeBBiH/veP4XPIPqw6u7Y6HwAoFQeg9ykNogOcNG4TrFragQeiCh8AKBUEIB5VDQIPw7lf4XPIPqw6uVSFDJx4CKxQEITwoZEjVo4dg1iDQJr7z5hBYoSAI4ZIzCO8aziGcz0NghYIghI9vEJ57x7SH0EEO4RyBIAjR4a9D+LPpHML8hnNnGc76QRCE6PE9BNMG4bqF6B20DxnOaqQgCHpoMwiGpx3VyU1+yHBOIwVB0IMyCA3wnGkPoZqSimgQ2EYKgqAH3yA8+45ZD+HqBS1iDATBOL5B+NNGsx6CGANBsAELDEKeFO0QBEvIGQRD6xDyRs3a41V+4RonCIJeyCCkG+DpDcfw+eQf2qjwSi1TA7iGCYKgH99DeHqDXg8h7/5XPwc5+08QLKPNIOjzEPKW7Thz/p1MgiCYwTcIz2hKKqr/9CvEi9Kaaa5BgiCYw88hPKXBQ1D/uX0Z7WJq5BsjCIJZNBmEb/9HHQwiswqCYCV+yPDU+ugMQtv/qESi5A4EwV58g/BkRAbhrB+8KigYMnANEQTBPH7I8MT6o/jInv0w95ZzBNNyWxrpolxjBEEwizIIjfD4unANAit88LXD3lFRVAlFjIIg2IfvIYR5LgMrzHH78n3eRakaChkH2ccgCPZAz2ZRPRRtCscgsMIgcz85BWQYRhbvRoMgnoIgWIMfMvT+oBbI+//sU6AIy6pkzAAAAABJRU5ErkJggg==IoT DeviceGE.EIRectanglefalseAnyAnyfalsefalseSelectGenericXamarinAndroidiOSWindows PhoneMobile Client TechnologiesVirtualDynamic84259115-f55a-44fc-9423-6c239e36e595ListA representation of a Mobile Client Application (Mobile App)falseSE.EI.TMCore.MobileLower right of stenciliVBORw0KGgoAAAANSUhEUgAAAgAAAAIACAYAAAD0eNT6AAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAABcRgAAXEYBFJRDQQAAEm5JREFUeF7t3aFTXMkaxuH7J65BrIhAICMQkYiIK1asiIyIiFgTEYFErEAiIpARSAQiMgIzd85sZbdDTt3ab5rQ89KPeLpgasie2eI7/ZthOPxns9kAAJNZvfH/ub6+3lxeXm4+fPhj8+bNm83Z2dnm+Ph488svvwDAFJZ9b9n/ln3w4uJic3Nzs90i1/fNQ7V640P39/e7B3hycrL6PwIAZrfskR8/ftx8+fJlu3Wu76eHZPXG1vJM3zN8APh3jo6ONu/fv98sT54f7qmHZPXGxXLgr1+/Xn1wAMD/9/Lly83nz5+3W+r6Pjva6o1fv37dnJ6erj4gAODfu7q62m6tP+61o63eaPMHgMex/EhgeQP9w712tB9uOD8/X30AAMB+Xrz4dXN7e7vdZr/fc0f67pO7u7tdqawdPACwv99+++92q/1+Ex7pu0+W32dcO2gAoN8hXS/g7w+WN/559g8AP8/bt2+3W+6Pm/EIf3/gZ/8A8HMtT7QP5UJBf3+wXNJw7WABgMfz6dOn7bb744b81P7+YHmH4tqBAgCPZ7m0/re9d6TdsrwpYe0gAYDH9e7du+3Wu74pP6XdslylaO0gAYDHdSi/Drhblr9etHaQAMDjWq62227Eo+yW5S/+rR0kAPC4lj8b3G7Eo+wWAQAAT0MAAMCEBAAATEgAAMCEBAAATEgAAMCEBAAATEgAAMCEBAAATEgAAMCEBAAATEgAAMCEBAAATEgAAMCEBAAATEgANE5PTzdnZ2cA8CSOjo5W96OnIAAa19fX28NYP0AAeGzLJry2Hz0FAdAQAAA8JQEgAACYkAAQAABMSAAIAAAmJAAEAAATEgACAIAJCQABAMCEBIAAAGBCAkAAADAhASAAAJiQABAAAExIAAgAACYkAAQAABMSAAIAgAkJAAEAwIQEgAAAYEICQAAAMCEBIAAAmJAAEAAATEgACAAAJiQABAAAExIAAgCACQkAAQDAhASAAABgQgJAAAAwIQEgAACYkAAQAABMSAAIAAAmJAAEAAATEgACAIAJCQABAMCEBIAAAGBCAkAAADAhASAAAJiQABAAAExIAAgAACYkAAQAABMSAAIAgAkJAAEAwIQEgAAAYEICQAAAMCEBIAAAmJAAEAAATEgACAAAJiQABAAAExIAAgCACQkAAQDAhASAAABgQgJAAAAwIQEgAACYkAAQAABMSAAIAAAmJAAEAAATEgACAIAJCQABAMCEBIAAAGBCAkAAADAhASAAAJiQABAAAExIAAgAACYkAAQAABMSAAIAgAkJAAEAwIQEgAAAYEICQAAAMCEBIAAAmJAAEAAATEgACAAAJiQABAAAExIAAgCACQkAAQDAhASAAABgQgJAAAAwIQEgAACYkAAQAABMSAAIAAAmJAAEAAATEgACAIAJff78ebf3jLD8tx8ezwi7RQAAwFx2iwAAgLnsFgEAAHPZLQIAAOayWwQAAMxltwgAAJjLbhEAADCX3SIAAGAuu0UAAMBcdosAAIC57BYBAABz2S0CAADmslsEAADMZbcIAACYy24RAAAwl90iAABgLrtFAAA/w+3t7eb8/Hzz+vXrzdnZ2eb4+Hj1HADsb5mrZb4W79+/33z69Gk7fusz2dotAgB4TDc3N7uT0dq8Az/fixe/bj5+/Li5v7/fjuT6nO4WAQA8lnfv3q3OOfD0Tk5ONssrcQ/ndLFbBADQa3mmsbzUvzbjwDjLqwFr++xuEQBAL5s/HK4lAu7u7raj+s/M7hYBAPRY3ni0NtvA4Tg9Pd2O6z9zu1sEALCv5eeLR0dHq7MNHJarq6vt2P41u7tFAAD7evPmzepcA4fn1atX27H9a3Z3iwAA9rG88W/52eLaXAOH6cuXL9vxFQBAh+WCI2szDRyuy8vL7fgKAKDDxcXF6kwDh2u5QNAyv7shFgDAPkafO4C65WJdy/wexBALAMjkDYCQZ5nbZX53QywAgH0IAMgjAIBuAgDyCACgmwCAPAIA6CYAII8AALoJAMgjAIBuAgDyCACgmwCAPAIA6CYAII8AALoJAMgjAIBuAgDyCACgmwCAPAIA6CYAII8AALoJAMgjAIBuAgDyCACgmwCAPAIA6CYAII8AALoJAMgjAIBuAgDyCACg2+gAePXq1ebs7AyiLN+3a9/PT0UAAN1GB8Dd3d32MNaPDQ7V8n279v38VAQA0E0AQJ0AaAgAyCQAoE4ANAQAZBIAUCcAGgIAMgkAqBMADQEAmQQA1AmAhgCATAIA6gRAQwBAJgEAdQKgIQAgkwCAOgHQEACQSQBAnQBoCADIJACgTgA0BABkEgBQJwAaAgAyCQCoEwANAQCZBADUCYCGAIBMAgDqBEBDAEAmAQB1AqAhACCTAIA6AdAQAJBJAECdAGgIAMgkAKBOADQEAGQSAFAnABoCADIJAKgTAA0BAJkEANQJgIYAgEwCAOoEQEMAQCYBAHUCoCEAIJMAgDoB0BAAkEkAQJ0AaAgAyCQAoE4ANAQAZBIAUCcAGgIAMgkAqBMADQEAmQQA1AmAhgCATAIA6gRAQwBAJgEAdQKgIQAgkwCAOgHQEACQSQBAnQBoCADIJACgTgA0BABkEgBQJwAaAgAyCQCoEwANAQCZBADUCYCGAIBMAgDqBEBDAEAmAQB1AqAhACCTAIA6AdAQAJBJAECdAGgIAMgkAKBOADQEAGQSAFAnABoCADIJAKgTAA0BAJkEANQJgIYAgEwCAOoEQEMAQCYBAHUCoCEAIJMAgDoB0BAAkEkAQJ0AaAgAyCQAoE4ANAQAZBIAUCcAGgIAMgkAqBMADQEAmQQA1AmAhgCATAIA6gRAQwBAJgEAdQKgIQAgkwCAOgHQEACQSQBAnQBoCADIJACgTgA0BABkEgBQJwAaAgAyCQCoEwANAQCZBADUCYCGAIBMAgDqBEBDAEAmAQB1AqAhACCTAIA6AdAQAJBJAECdAGgIAMgkAKBOADQEAGQSAFAnABoCADIJAKgTAA0BAJkEANQJgIYAgEwCAOoEQEMAQCYBAHUCoCEAIJMAgDoB0BAAkEkAQJ0AaAgAyCQAoE4ANAQAZBIAUCcAGgIAMgkAqBMADQEAmQQA1AmAhgCATAIA6gRAQwBAJgEAdQKgIQAgkwCAOgHQEACQSQBAnQBoCADIJACgTgA0BABkEgBQJwAaAgAyCQCoEwANAQCZBADUCYCGAIBMAgDqBEBDAEAmAQB1AqAhACCTAIA6AdAQAJBJAECdAGgIAMgkAKBOADQEAGQSAFAnABoCADIJAKgTAA0BAJkEANQJgIYAgEwCAOoEQEMAQCYBAHUCoCEAIJMAgDoB0BAAkEkAQJ0AaAgAyCQAoE4ANAQAZBIAUCcAGgIAMgkAqBMADQEAmQQA1AmAhgCATAIA6gRAQwBAJgEAdQKgIQAgkwCAOgHQEACQSQBAnQBoCADIJACgTgA0BABkEgBQJwAaAgAyCQCoEwANAQCZBADUCYCGAIBMAgDqBEBDA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 ClientGE.EIRectanglefalseAnyAnyfalseA representation of Active Directory Federation Services (ADFS) ServerfalseSE.P.TMCore.ADFSCentered on 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GFlCgDMTQGAPmJYmQIAc1MAoI8YVqYAwNwUAOgjhpUpADA3BQD6iGFlCgDMTQGAPmJYmQIAc1MAoI8YVqYAwNwUAOgjhpUpADA3BQD6iGFlCgDMTQGAPmJYmQIAc1MAoI8YVqYAwNwUAOgjhpUpADA3BQD6iGFlCgDMTQGAPmJYmQIAc1MAoI8YVqYAwNwUAOgjhpUpADA3BQD6iGFlCgDMTQGAPmJYmQIAc1MAoI8YVqYAwNwUAOgjhpUpADA3BQD6iGFlCgDMTQGAPmJYmQIAc1MAoI8YVqYAwNwUAOgjhpUpADA3BQD6iGFlCgDMTQGAPmJYmQIAc1MAoI8YVqYAwNwUAOgjhpUpADA3BQD6iGFlCgDMTQGAPmJYmQIAc1MAoI8YVqYAwNwUAOgjhpUpADA3BQD6iGFlCgDMTQGAPmJYmQIAc1MAoI8YVqYAwNwUAOgjhpUpADA3BQD6iGFlCgDMTQGAPmJYmQIAc1MAoI8YVqYAwNwUAOgjhpUpADA3BQD6iGFlCgDMTQGAPmJYmQIAc1MAoI8YVqYAwNwUAOgjhpUpADA3BQD6iGFlCgDMTQGAPmJYmQIAc1MAoI8YVqYAwNwUAOgjhpUpADA3BQD6iGFlCgDMTQGAPmJYmQIAc1MAoI8YVqYAwNwUAOgjhpUpADA3BQD6iGFlCgDMTQGAPmJYmQIAc1MAoI8YVqYAwNwUAOgjhpUpADA3BQD6iGFlCgDMTQGAPmJYmQIAc1MAoI8YVqYAwNwUAOgjhpUpADA3BQD6iGFlCgDMTQGAPmJYmQIAc1MAoI8YVqYAwNwUAOgjhpUpADA3BQD6iGFlCgDMTQGAPmJYmQIAc1MAoI8YVqYAwNwUAOgjhpUpADA3BQD6iGFlCgDMTQGAPmJYmQIAc1MAoI8YVqYAwNwUAOgjhpUpADA3BQD6iGFlCgDMTQGAPmJYmQIAc1MAoI8YVqYAwNwUAOgjhpUpADA3BQD6iGFlCgDMTQGAPmJYmQIAc1MAoI8YVqYAwNwUAOgjhpUpADA3BQD6iGFlCgDMTQGAPmJYmQIAc1MAoI8YVqYAwNwUAOgjhpUpADA3BQD6iGFlCgDMTQGAPmJYmQIAc1MAoI8YVqYAwNwUAOgjhpUpADA3BQD6iGFlCgDMTQGAPmJYmQIAc1MAoI8YVqYAwNwUAOgjhpUpADA3BQD6iGFlC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ADFSGE.PEllipsefalseAnyAnyfalseAzure Active DirectoryfalseSE.P.TMCore.AzureADCentered on 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 ADGE.PEllipsefalseAnyAnyfalseA representation of Azure Data ExplorerfalseSE.P.TMCore.ADECentered on stenciliVBORw0KGgoAAAANSUhEUgAAADwAAAA8CAYAAAA6/NlyAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAAFiUAABYlAUlSJPAAAAQ3SURBVGhD3djNa9RAGAbwnvyD9ODRox78BwQVD3oQRD14qAp6EFSoINiDXgQFQURBlFJsVbSVHsQiiq390NrP3e2XLda223a7HfsMeddJ8iaZmUyy2z7w0CWZyeZHdzPZNJ14WhBNzX117Z7L/eLQk0FxpG0os57q/CkuvZsSTWI79UTnhv0w/h+M1AOdKzYIRvJE547lwEge6Lpgo8BIlmhT7OnXI+L+t2lx9u0vdj9XFhsHRrJAm2KBnF3dkOezslEVzd1j7Di1kVg0Doy4RKfBUpLQsVg0CYy4QNt8Z8f+rHln4M/iWkUcbx8OjU/EojpgJA3aBgvQRnXLe3d/sB3fa3W8FhbVBSM2aBss9e6XkvfO/jwemPON08aiJmDEBJ0GSw2inw3P+/YbYVFTMKKDdoGl3vlcFP3zK3JpUrcbY1EbMBKHdomNqhUWtQUjHNoUi6UHV2MsPzprLBrEtn4uyfnF5XX5Wt0XahowoqJtsOo6q3NjwWHLlap3BCFfx6LTghGg02Ipcegg9nZv0YelYBv2qWNrdQFGjj0fZU8yqrjaRqVr8k9oPPed7SkseTPC+Vj6Gxov6wqMHH2hf3N/8+OUNysc3avxg74Zb0Y42MfNcQpGTNDcjYXpOst9UrCNGyvrGozYom1vKlR0LBbNAoyYoHFfjIuYuk0XS235VJDl9vmaFRgxQasNYgHpGF3UAyU1SzBiig5i1XU2cY3VqS14avGlGCy1iOrWurclOrroOCwlDbq5a1xce180B/+YuSde9e2V/TR6xgma+84ulCvebH+W1jfFlZ6J0Pi4Anvw4Yi41T1nBlaxrtAcFqDgf5dSqW6JG9vreHBOVAm7r9UQzGGpQOskiOawVG6NRRKXHqUq1ggch0W7hg57I5ND6DgsNYhOg9UG62BXNwreaL2cbBtjT5Lro++zYmihLP9y+7lyWC1wFljK+U7+ZNM2CpsIzhJLcY2Ow6KRYBfYymb0zzc1rtBJWJQFu8DSMb4Vrnpb4pMWrYNFQ2CXWGrWaF0s6gNngaVmhTbBojVwllgq7r91oos2xaISnAcWx1irRD/HCiYJbYNFJZg7QaorbNIxuEShbbGoBL8ZOGB9ollhKUF0GiwqwUvlQRFENwKWQui0WLR20VLReWGHZ+7I6uRc50RqLFoDI0DjKUYeWCxTNF53ybrQPs0iTOoD68Q1lpoX2gicFZaq+/FOg9YGZ41Fv05e9EYmxxatBc4Dq/tcTI0NOhHcqFiKKToW3OhYigk6ErxTsBRdNAveaViKDjoE3qlYShLaB97pWEocugbeLVhKFFqCdxuWwqElmDtBqg4Wj264udR6YClBtASneQCA4FdWR99+9hj1xFJUtATbPgBQM/e3J4RuBCyF0LWLlukDAC4qupGwFKBrYATo/uJ1Kyzl93Kv/JnXaFjK11JZ/APE8zEB5VpUdAAAAABJRU5ErkJggg==Azure Data ExplorerGE.PEllipsefalseAnyAnyfalsefalseSelectOnly AzureAzure and On PremLinked Service TypesVirtualDynamicafe0080c-37dc-4d53-9edd-d0a163856bdcListAzure Data FactoryfalseSE.P.TMCore.AzureDataFactoryCentered on stenciliVBORw0KGgoAAAANSUhEUgAAAgAAAAIACAYAAAD0eNT6AAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAABcRgAAXEYBFJRDQQAAHIVJREFUeF7t3S+UXMXW8OErr7wSiUQikUgkFomM+ATiiggEIgIRgUAgIhAxEREIBOIViAhEBCICMQIxIiIiAhEzX3ZYfZl0dqp7prv+nKpHPGYvFumZVM759elTff51dXUFACwmHQIAc0uHAMDc0iEAMLd0CADMLR0CAHNLhwDA3NIhADC3dAgAzC0dAgBzS4cAwNzSIQAwt3QIAMwtHQIAc0uH9Pf08q+r//vjHw9+e3H19c/P/+fuT8+vPv3u4qD/3H129a//97aYZf/tvut/3r1fnr/1euL17b9mALYjHVLPs+ev3pxAH//+8n8n190J94Ov/3jnZL0F//7vP0ERYRI/08OnL9/8nPHz7v8OAOgvHXJ7f70+38WJL06AcSL84sc/35wY4ySZnTxXsYuELx9evvm9iAOAvtIhh12+fHX18zMn+XP45P7F1ecP/nzzu4wrI8IAoL50yNvi8+54R7/73D37XJ3z2l0xiN95/O5FAcB5pcOVxTv7OOHceXT55p1pdnKij+tREFcKXry5DzH/ewSgLB2u5OLFqzd32Mdn0x/d2+ZNeCuLSIsgiI9j4v6L63+3ALxfOpxZvMOPE358br/Vu+55v7hCEPcSPLmwTRGgJB3OJk4G8S7x429d0l9J3KsRV3bi4wJXBwDelg637vq7fDfsEeL+gdhpEOsi1sf+mgFYTTrcorgh7PsnL95cAs5OAHBdrJNYL24kBFaVDrciLuvGO7p4Z5cd5OGQuDIQHxPETYT76wtgZulwdLFNLy7v++IdzunDb/54c69I7AzZX3MAs0mHI4rPbeOBNO7cp4XPfvjTVQFgaulwJHEQjnf72UEaaovvhoiPmewiAGaTDnuLg228249LstlBeTWxfTFuWtsX71Jjz/v77D/CN8Qs+2+vi/9v9uet/JFLXHmK340dBMAs0mEvceK//+uLJS7z706q10/icVf67kQ9+ufQ16Ni9/rD7uea9WuUI4K+enxp9wCweemwtRlP/NefcBeXkONEuepJIx7kEz9/BE78PuL3EpGw5e9oiNceV1N8NABsVTpsZYYTf5zorz/j3iXim4koit9brIO4Az/CY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 Data FactoryGE.PEllipsefalseAnyAnyfalseA high-scale ingestion-only service for collecting telemetry data from concurrent sourcesfalseSE.P.TMCore.AzureEventHubCentered on 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Azure Event HubGE.PEllipsefalseAnyAnyfalsefalseSelectAllow any IP inboundAllow only other Logic AppsAllow specific IP rangesNw Level Access Control Config for TriggersVirtualDynamicd488c23c-1667-45a1-994b-f56f2655727bListfalseSelectNoneSpecific IPNw Level Access Control Config for ContentsVirtualDynamic0b0ab9bc-a582-4509-a6c4-8d56de65661eListfalseSelectYesNoTrigger_action has sensitive inputs_outputsVirtualDynamicb1724997-7ae6-4b30-a001-9c5b42d9d1d1ListfalseSelectYesNoHTTP request based TriggerVirtualDynamic5afb52dc-dffb-4319-aa22-523f78ee3845ListA representation of Azure Logic AppsfalseSE.P.TMCore.ALACentered on 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 Logic AppsGE.PEllipsefalseAnyAnyfalseA representation of Azure Machine Learning ServicefalseSE.P.TMCore.AzureMLCentered on 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Azure MLGE.PEllipsefalseAnyAnyfalseIngests and processes high-volume data stream falseSE.P.TMCore.AzureStreamAnalyticsCentered on stenciliVBORw0KGgoAAAANSUhEUgAAAgAAAAIACAYAAAD0eNT6AAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAABcRgAAXEYBFJRDQQAAM4FJREFUeF7t3S2UHcfVqOEPXhgYaBgYaGgYGBoYaHBBwAUCBgYGAQIGBgEGASIGAQYGAQYGAgECAQIGAgYCAgIGAiZz9WpWf3OmtM/M+enu2rXrBc9a9+7P0ZxTp7tr166f/p+bmxtJkjSZMChJkmoLg5IkqbYwKEmSaguDkiSptjAoSZJqC4OSJKm2MChJkmoLg5IkqbYwKEmSaguDkiSptjAoSZJqC4OSJKm2MChJkmoLg5IkqbYwKEmSaguDkiSptjAoSZJqC4OSJKm2MChJkmoLg5IkqbYwKEmSaguDkiSptjAoSZJqC4OSJKm2MChJkmoLg5IkqbYwKEmSaguDkiSptjAoSZJqC4OSJKm2MChJkmoLg5IkqbYwKEmSaguDkiSptjAoSZJqC4OSJKm2MChJkmoLg5IkqbYwKEmSaguDkiSptjAoSZJqC4OSJKm2MChJkmoLg5IkqbYwKEmSaguDkiSptjAoSZJqC4OSJKm2MChJkmoLg5IkqbYwKEmSaguDkiSptjAoSZJqC4OSJKm2MChJkmoLg5IkqbYwKEmSaguDkiSptjAoSZJqC4OSJKm2MChJkmoLg5IkqbYwKEmSaguDkrSlV29/u/nx53fD4PO230EaXRiUpC199vWrm//5vy+Hwedtv4M0ujAoSVt5/etvYSeb3cs3VgFUSxiUpK188/xt2MFm9+T7N+8/fvydpBGFQUnaymjl/8Xvv/j5/cePv5M0ojAoSVsYtfy/+OHlr++/RvzdpNGEQUnawtOfxiz/L/787S/vv0b83aTRhEFJ2sIf/z5m+X/xf/7fyxuqGO33kkYUBiVpbc9fvQs71dFQxWi/mzSiMChJa/v8u9dhhzoaqhjtd5NGFAYlaU3vfrv5UD6POtQRvXj97v3Xir+rNIowKElrGnXv/zF/+9fr918r/q7SKMKgJK1p9MV/rd89eXlDVePwO0qjCYOStBbK5VEnOrpnLzwTQGMLg5K0FsrlUQc6uj/9wzMBNLYwKElroExOuTzqQCvwTACNLAxK0hq+/U+txX+tL37wBUEaVxiUpDV8+rTW4r/WJ1/6giCNKwxK0rV4f37UaVbz48+eCaAxhUFJulbVxX+tvz7zTACNKQxK0jVY/Mf786MOsxpOOPRMAI0oDErSNdgjH3WWVXHSYdsGUnZhUJKu8dnXtRf/tVjs2LaBlF0YlKRLzbL4r8X3bttCyiwMStKlnnz/Juwgq+N7t20hZRYGJekSMy3+a/G92/aQMguDknSJf/13rsV/Lb5/2yZSVmFQki7BC3KijnEWf/7WFwRpHGFQks716u2ci/8OcSaALwjSKMKgJJ2LF+NEneJsnv7kmQAaQxiUpHPNuviv9ce/eyaAxhAGJekcsy/+az1/5QuClF8YlKRzsPgt6ghn9fl3viBI+YVBSToVi96iTnBmv3viC4KUXxiUpFN99W8X/0V4IVLbVlImYVCSTvXJly7+i3AmQttWUiZhUJJO8cNLF/89hLMR2jaTsgiDknQKF/89jLMR2jaTsgiDkvQYFv9x8l3U8ekW0yNtu0lZhEFJegwn3kWdnu778WfPBFgT7UnlyemV64VBSXrMH75y8d8p/vJPFwOugQ7/cMqJ6opJwHXCoCQ9hFHYYSen45gmefuhCBC3pR5G2z35/k043WQScJ0wKFXx4vW7G86o/+uz1zcv3/igWAuj2vZhrOO+ee4Lgi5Buz32jgmTgMuFQakCOn9OZDt8WLA3m61r7X+r0zEic/HfeT596guCzsG7JXipUtSWEZOAy4RBaXRR53+IBwajC49rPZ+L/y5jBepx53b8h0wCzhcGpZE91vkf4r9jftEHx+kufUDP7m//8gVBx1CVW+O6Mgk4TxiURnVO599iXtvXuD6M9onaTo9jLtuK030sJv3s63UTSpOA04VBaUTXdP6HmK/99j8u2oqwmDJqM52GEnfbpjPaouM/ZBJwmjAojWatzv8QIzbedMeJd+3fm5GL/67HPva2XWfCfbplx3/IJOBxYVAayRad/yE6PbcR3m7JitpHp+NamjGh5B7t8d4Ik4CHhUFpFFt3/i22Ec5axnXx3zqoKrVtW1Wvjv+QScBxYVAawd6d/yEeKrNsI2TEyk6JqB10Po5Qbtu4GjrcTIdFmQTEwqCUXc/O/xCfge1dFR8urPh30d82aNeK1wzfKes1YxLwsTAoZZal828x4qnw5rdnL379sBMi+o5aV5WTKTN3/IdMAu4Lg1JWWTv/Q8yVj7aNkBX+nPDHAzL6TtoW0wJcM6NNKTE9RAUs+k5ZmQTcCYNSRiN0/ofYRvjFD7m3EfIg/Py7127vS4JrhvUW2XcKLB3/qNeNScCtMChlM1rnfyjjNkLKzr1XZ+thXDNc9+1v19PoHf8hkwATAA1g5M6/xSEovbYRUl6mzEy5Ofpsyon1GKzLaH/PPTFFRDWryn24mD0JCINSFpU6/0M8eNhGyIP18PtugVEbD+/H3quu3LhmWKexxzWzqNrxH5o5CQiDUgZVO/9DfL+tthHSfiOszNZ5uGZYt7Flp0W1qHrHf2jWJCAMSr3N0Pm3mJNfYxshUwx7nbeuvta6ZhZ0/FQZZqwWzZgEhEGppxk7/0PLNsJztoS5jW9u124jnLnjPzRbEhAGpV5m7/wPnbKNkIcVUwi2mXDKNdNiLYrrQ+7MlASEQakHO//Yso2Q9lnairKv2/h0THTNtKgYWDGKzZIEhEFpb3b+p2Fu37fy6Rzt1lM7/tPMkASEQWlPdv7S9ujQ7PjPUz0JCIPSXuz8JWVWOQkIg9Ie7PwljaBqEhAGpa3Z+UsaScUkIAxKW7LzlzQitky2z7ORhUFpK3b+kkbEWQmXHrSUVRiUtmDnL2lUnJTYPtNGFwalLZAARDeWJGVWcfSPMChtxdPrJI2m4ugfYVDailUASSOpOvpHGJS2ZBVA0ii++veb94+t+Fk2ujAobckqgKQR8FKlc96sOJowKG3NKoCk7HjVdvvsqiQMSluzCiAps+qjf4RBaQ+8rzy68SSpt+qjf4RBaQ9k12TZ0c0nSb3MMPpHGJT2QpYd3YCS1MsMo3+EQWkvVgEkZVPx1b+RMCjtiX220U0oSXtjh1L7jKoqDEp74pQtTtuKbkbdzkd+9vWrD/70j19uvvjhzQccT/rjz+8edDiPyf97iX/7n7f/++/85Z+//O+/78uaNDt2KC33THVhUNobnVl0M87g06e3nS+dMdWQpZNu22hvbbLAZzRRU2Uzjf4RBqW9Va8C8N2W0TsdKh3rqKuM+a34/CRtLJYiMXAdhyqYafSPMCj18K///hrelKNZSvZ09nynGbYTgYVTJAbLtMIfvrJaoHHMNvpHGJR6+ePfX4U3Z2Z0dIyEGdm/fDNHZ38qkh/ahUOfPvnShEB5zTb6RxiUehmhCsBCOUa4dGyzjO7XQoL0zfO3H9rP9QTKgnU47bU6gzAo9cTNGN2kPfGZWKA34yhhS7Qnawkov7qOQL0w8GivzRmEQaknOoXoJt0TnRGj1Gcvfr1h0dvh59N2nr96d/P5d6+tDmg3TDu21+EswqDUW6/XBbN4j9L+2w8D/fizaR8/vPz1w9oBzybQlmYd/SMMSr3tWQVgER/l/VmO/xwNFRgqMVRkot9PutTMo3+EQSmDLV8XTImZlfuu2h8LlRkqNFRqot9VOsfMo3+EQSkDVtivvTCM0T4diPP64+P6YAGh5w3oErOP/hEGpSzWel0wawo4pKb991UDv22vdSMaE8ljex3NJgxKWVxTBeB/x4py5/bnwZTOllNHqoEpQKuAJgAawLmvC+bEOf43ruSfF4njk+/fuINAIUf/t8KglAmZ+in7wvlvuLHN7LUgCeSa8FwBLRz93wmDUjY8xKObGYzyeAGNI349hMWfI75rQuty9H8nDErZRFUA5vhZJGjHr3NwwJDbCOfk6P++MChldPiiIBb3VX8Rz/J6XUYsVDgWHIhDB3bo3Llu/vvlf8vq+eXf5m/xN2dYOMn15BsK58LaoPY6mFkYlLJiYVelzokk5rCTp0POVKbmJUh/+sdtgkAJnbP62+8wMkaDdAouFqyPimH1QcO5wqCkdTFNwYiTjpQONeMbD8/B56cKw6t9KyQFdAx8n+i7qgamC9vffXZhUNJ1lg6fh84MC88YXTGVQEIwcoWGd1BQhYm+o8bl6D8WBiWdh1Iyi8uYonCl+e2RyyQ/tEnbViNwfUAtjv5jYVDS45YOf/Ry/tYYfbFwkTUEI43CXB9Qg6P/48KgpBjz3cwV2ylcjgoJiRPl9rZ9M6Lz8FXE43L0f1wYlHSHOW0W71kSXh9TBawbGOEsByoYJn7jmWFL66XCoDQ7OiQ6Jsv7+6BMS2WFl/m0v0UmVAO8JsbBwtT2N9SdMCjNisVflHvpkKIHirZHB8toO/OJbawN8BrJb5Rppl7CoDQTSoSMPn1hTC6U2zNXBehcmMKIPrv6c/T/uDAozYCO33fHj4G9+c9e5NtSSJWCBY3RZ1Zfjv4fFwalyngwuKp7TCzEZHqg/U17Y0uoFaQ8HP2fJgxKFdHx82CIHhgaC1sJWa/R/sY9sXDUxDIHR/+nCYNSJbxsx+Nda+J35fdtf/Oe2D3iAsF+WETa/iaKhUGpAt/7Pg9esJRp1MeBUZ4Z0Ee2ylBmYVAaGR2/5/HPiRJ8loNf+BzuEtgX9337O+i4MCiNyCNbteD41wznv7MuwCrUfjIuEM0sDEqjefqTx7TqPubh2aKX4UAhzjOIPqPWxbbetu11XBiURsFcq0ez6iGU4blO2mtnbySp0efTekj6fPPf6cKglB2lVcq80UNgBjzoKC0fYvqDlxZF2P54+N/OWC3JUA1ggZqVqm1xvbftrlgYlDLjIVr90JXDDp3vu/UIlhX0bKdjCxuJFX+/4la2DNUA2to3S26HZ0Pm90hkEgaljFhVzXav6KYfEZ0AHS0jU8rDdMDZype0ObsqlipClVXtvMyn/a574nd2p8p2XAx4mjAoZUI2X+Hta4xMGNXzcMqyVe1SJCskLSOvv+Cz93zRENe176LYhtsBTxMGpSzoKEftZJjrZdRMWT37e+6vwWiWpIbvOlqSxuftXQ3w5MBtZDshMqMwKGUw2oIpHuJMUTAynvUscka1/G6MbEdap9G7GuC6gPWRkLbtrPvCoNQTnchIK/zpPBgBszPh8Hvodpsmv+UInRsJHMlb+x32wvVDpxV9Nl1m9Km2rYVBqZdRSv50aCyM8wFzOt7nz6LHqD0z4dCenqvInRJYD8ln2766EwalHrKX/HkoU9p2bvE6lLuzL34jCe1Z0WE6wl0C1+Oe7ZnMZRcGpT1lL/kzr0+J3wfJulg8SBUl61oBqjw913JwvbFFNPpsOl3PaZ3swqC0l8wlf0aplvi3R0dHgpVxxMsIkspU+5n3NNpi2GxI5No21a0wKO0h44NtKfPb8ffB9ErGdQK9j5dlSsBdApfrncRlFQalrWUr+dPx85l8kUgOPLCzdXgc4tRzGshXC1+Oaby2PWUCoJ3xAM201cmOPy+uFUbe/EbRb9cD0xS9q0OZ18tkNuvZHA8Jg9IWGMFkOcvfjn8c/EaMvqPfsQcWLfZ+oRCJUfTZdBzbO9t2nF0YlNZG559lkRcrq+34x0Onm2XBKAkkL0lqP+OerASch9/M+/6+MCitiZJphvlcOo/eIzddjwOFMmwdzJAEZD9PIZve733IJgxKa8lwxjk7Dbzxa2F9QIYRcO8kgHao9IrsrZE49lzImU0YlNbAaLv3Nj8WHFr2q4vOt3c1IEMSMMLx2VlQQWrbcFZhULoWD0QejNENuAc6hd7lWe2DBK/3KLh3EsAaG88JOA1rkdr2m1UYlK7BqW49O38W+Vnmmw/TPD2vu95JAIcFeWLgaVwLdCsMzowbmLlFDtwAW0d81evpOHc7uuH2QBnUvb5z4/f/w1f9RsK9kwBOUow+l+5jarBtuxmFwRmRET5WQiMZcD75uJ4vLun9ClflwXXA9RBdJ3vonQR4RsBpfJabAHzAsaPRBRLh5nYRycd6bUfy99AxPd810TMJcFHgaaj0tm03mzA4E/aoX/KQcFvZnV6dPxUbS/56CPd3rymBnkkA6wH4+9Hn0i2e+7NXDcPgTK5ZPezRkv06f34312XoFFwnvUbEdMLMy7efaQ+eFPg41iy17TaTMDgLSsfRRXGOmTuiXp1/71ezajyM9Hq9hIr7pP08e2COO8OJiZnNviUwDM6ATnutmyPDG8L21OthSsnO93rrGj0WB/bsZHruyhkF07mzDuLC4AzWvjFIJmaYj2ZU0eOlPvxN5jXbzzMzrjfKy49xz/N9PPCja2xLvToYkvWe2yJHwqCGqvBM6wLC4Ay2GAkw31d5hEqH06OkyDTLbIt16Li5lpjuoITMmRRrLeqikrKcc8G/TYfI35tpWxRne0Rts5WeSdg5u5x0+xzn9dMzJANhcAZbLgqquLCEh0iPVcXVO3+qGt88f/thQSkdcu852yU5YAEZ1zGJQdX2Z4X+Xtc07dj+/T3xm0afSw9bkoGqA7swOINLtv6dg5FVlQdnj5IpuPGqdT5Lh893G2mBFgkz10G16QSqWls/C9D7rAq+Z/S5dDquE57rlZKBMDiD6AdeG3NvI89bM29JRxV9t631Wjm9Nn5/RtLML+7R0eyB78F1QRm9wrTBHkkAbdX+3b312gVR0ZIM9K7sXCsMzmCvN2dxoYx4Uh3l0V4j1NE7f3aEMFqeZfEVCzQ5BnrkZHfrJCDDqNEqwDZ4TjKFN2IyEAZnsHc2zN8bYbTEZ7zmcKRrjdr5Uy1hlDf7XCtTBbTDiFM3W64JyJIcWQXY1pIMkGy1bZ9RGJzBGocAnYsRBiPD9rNkQMfPwq8eC/0W3Djt58qO64hyeM92y4hrnd9ztKoASUD0fa7BtdH+nV6sAuyHKjPP1MzJQBicASOUXiVuSqZZFpJk6Pgx0ul+S5ttWTKuhKkQFj6OctjK2lsEex4EFLEKsD+SgYzTZGFwFr1PyeLB2GtxECPXnqX+Q6N0/lmSpVHRbrQf7di2bTYkLNF3uATfuf33e9qiyqHT8dznmZchGQiDs+hZBTi0V6mIG5+ybIbvvGAU3X7ObFjUR7vZ8a9jSQSyVwR4SEef/xzcaxnXQ8yyQDU7fgemhXsdJR8GZ7Jmpr+GJRmgs75mpMRDh1WpVDmyjPRbLJjLvHKWm5JFidFn1/VI/uhkMycClG2jz36qrHvGe1c/9TGmivhd9kwGwuBs1sj0t8IIgg6cz7ggaaHj5OFyGCdxyHCa3Cn4vO3vkIUd/764XnnwZd05cOm1wOLQ9t/KgqTLilZeJAM857eeLguDM6JDin4IrS9r508HxIjPB2MfJAIZDsyJnHsaJpW87FMcJrljYFC3VTIQBmdlErC9rJ0/Uy7Oi+bA75DxyGGuETr26DMf4vOPsA/cLYHjIRkgSV4ruQyDMzMJ2E7Gzp+sutdxx3oY1ZiM0wI8gKOtdCQHVAqyTmVETHrHxTV4bTIQBmd3brlPj8tY2mXe2b38uWWtBixIIEd+QdK1ixyVw6XJQBjU7etv7RzWka3zp/S55eugtb6s1YDRsZg4am+N65xzJ8KgbnFQgyWyy7GYLlvn7xTPuLJXA0Y1wq4hnY51Au1vfEwY1B1KKjRo1NA6jodKpoc1pVp/xxqoBrS/ry7nboBaTAA2QFklamx9jPL61vtXz0Ei4iinFs7GyL7NbhRMd0ZtrDGZAGyEbUB2JA/jyNxMc7XVTjzjgBBu8AXtzbRGZDkYalFtTQtTAr2OUK2E+9WzL+rgXm9/42PCoI5j1GHJ7GN0Lpnm+/mdRnzrGQ9ibmC2JtKJ06Ys1FqzokLbLMdEk0Dw90btALjuMh8nPQoSy6h9NR4TgB1YDbhDR5up5M8q/1MObMmAjpdyNltPe6+ZYDTNdc0c+0gdAm3ISWnt99HpnOKswwRgJ7NXA+hk6TDadumJjiD7aDZLh/8YkjoqEFQjRpg+OGf7k+7jd47aVOMxAdgZI04aPfoxqsq4L5uSefRZM+D6IDkZeeEaCQu/e+bqCtWokdu4F48FrsMEoBPmIivPpTGyZs4448KrjJ0/i9QY6VdcqEblJ+trprkHTQLO58FnNZRLADiQh/JeO+fO/58Oif97+7/p6dmL014aMgoeDIz8Ms3zH8o0DbMkSdmuya2Q3HBtZFsPYxJwvtmqmFWVSQC4gXm4RF+yxUM32w3PKGnkF82QxDCyzvwgzdL50wFmb6utkfhm6kRMAs7DMzRqR42lTAJwbomRL57xvHBGzpSCR6gKLFWV7AvU+J0zlKD5TdlOl/G664XEN8tUmEnA6XwJWg0lEoBTR/4tRoTtv5XJspAqywMSdGK0W7YV/cdk6Pz5/bK95yCbLFNhWQcG2fB7Re2nsQyfALAi9ZqtXNmTgAXzp6wMZ+XynlvXuEBIQjgCNOu8/jGM5nq+yY8KiR3/ebjGe68RIGE0CXgYg5Oo7TSW4ROANUbHI+4JpjNeTmhbjnG9dGUuK9D53/PvMDfN6D57Wf8xdP49Kye0peXky9D5UmLueUaDScDDeP5E7aaxDJ0ArHl2Ox1f+++PjqoBSUKr/e+q4Xv36vy5oWZZ1b812rFnBcck4GE9EzStY+gEYO253YpJwGzo/HvMJVO2Zl60/Ty6Xs9qwIjVwb1QOYzaTOMYOgHYYq7QJGBcvTr/jNtKq+lVDSDxGG3ty17oPKI20ziGTQB44EZfaA0mAeNhMejep5Px91gc2X4WbadHNcAqQMwEYHzDJgBbr0Jl5Xv7N5VTj86f0SgVh/azaHv83ntWeqwCxEwAxmcC8AC23LkIKDcWNe7d+ZMcel30RYe855QAlYf2M8zOBGB8wyYAe21DYTW52X9Oa+4COQWJxigHIM2AJGyv47N5DrR/f3YjH12uW8MmANhrFSrlRsqO7d9XH6z/oDoT/VZbMRHMizU70W+2Nqs+92V6sZYuM3QCsOd51MwDuuCrP1aD7739yP3g+bEFc+vFga75uM8EYHxDJwCMyPZeEUzZuf0c2gcJ2N7z/ZQ57fzHsPViULd63rd3FU7rGzoBwKUvAroGI0LLwftiK1b0W2yJ/f3t51BuWyUBnDnS/q3Z0XlEbaVxDJ8AMDrr8fIQHjK+6GV7PNB7HADjWRDj2iIJIOlv/87sPAlwfMMnAOj5akqrAdsgsetR3YGJ3fjWTgI8DOhjGV7frOuUSADAQzv6gnuwGrAuttr1eiWs+73r4DpaY42QBwHF9l5/pfWVSQDQMwkA1QBXCl+Oh2zvvcUmcrWskQS48DcWtZXGUioBQO8kAJQLHTGcjnI/D9ktFm+dg7/vq3zruSYJ8ACgGAOdqL00lnIJADIkATxwmMN269BxS8ffq9x/iM6feeP2M6qGS5IA/nsTwhjtGbWZxlIyAUCGJAB0LKwody/5nUwdP6qd9EjSyTsSWBzLtceBLdzop2Aai//Nggd9lbbhe5xzzXnw13HfPM/xfNV1uOfb3/aYMJhZliQAPHjo9GauCGTr+EHnP/K6DV6KRZuydmLr7ZK0FQ8MKlvcWyO2G9cgCz0fmm5iexvt2v5vdafHuRxaX+kEAJmSAFBWZEQ20wOGjoLRZKaOH8zvjtaJMSqlA+bGjb7T3kgKuJ5HTAhoS65LkicsFY/2v9PHPAWwhvIJAPY4J/wSjDQopVWsCvCd+G49DvE5BZ3/KO1OOZ9TCXsvkjwFCQGjQ+fOa/MQoBqmSADA/B8Pp6gReqtUFWBUxWgqY8K1ICnJ3vnTgdKRZquanINOgnL7yFMsimW+v3W6aRIA8NDPUjo9hlEeHSgl1RG2EvJw57OSwIzQWbHILfOCTBLViuVV7jsqce331Xi4RqPfWOOZKgFYjLSAhVI1c75ZqgOHHX7WisoxtGP7fbKgzJ89OV0D1wxTQ+6KGReLTqPfVuOZMgFA1nUBj6GsumzV4jtstUWLBzSdEg9r/hYXymgd/oKqStYtXSR2WddJbIlqEdeVB2aNxwWAdUybAODcfcGZUSngxwQP1kN05C2y+Pa/Y6EZ//sRFpudis414xw001FupfLArBFVej7MbuoEAIxAZhyBzYCEJmOpmcpNlcRzLbQHU0ttWykX5/9rmT4BWLBa2ZWtNfA7ZlxwRrLJ9E30mXWLZNxDePJy/r8OppPPSbrDYCVsvbIaMDYu6ox70Jl2sXR6OnbCuD4gHxPYsbGOiym3S56RYbAiqwFjYk49Y8nfUdNlMi/enBHrNHwujofpNaZDr10wHgarshowjqxlY5IRRrLRZ9bp2HLqIsH+KBdHv4/yIXnmvlnzaOswWJ3VgLy4yBldt79ZBiSQ7MyIPrfOxyjGc/r7svyfHwMO1j9tUQkNg6fgA7HNjAuIUgT/b+ZE2/8uKx7mrJaMGlx9ZJ4jptTmfP82su7sqM7yf170q1Rntq6ShcGHMH/30HYn/m8cNNP+77IiaXFU1xeL/DInj3b+22PKxwWC+7L8nwv9EH3nnvdBGDyGUX70wSM81Ed6YQiJjYnAvuhUmY7JPPqz898Pgwe3C+7H8n9/9JP0q736yjAYoYOMvsBDeHBeu0pxb2TFox6POwquCy767IvARu78Ke0yxTXaKZB87pEqiKNiCjRqf22P/oXdTRn6xjAYYfVh9GUeM2ISABKBh6Y6dD7akwV+I8z3MhLN3HHyEGEERyLFepxzRs7cj8sanqwJAusC2s+t9Xhk9b64x7ims011hsHIpQkARk0C6KgYjVCmib6XTkNnRUI1ykIvVqZnWxzF5+GFLSRQlxz48RgSCA4TyTQN5nkB22CO2cV/26ONWdic+ToOg5FrEgCMmgQseEDSBt44p6MzoeNv2zKzbJ0/o/yttgAdw3wkI8TelQGun/az6XoeYrUtEvW979lLhcHItQkARk8CwLy1VYHj+I25Vkbc352l82eqpOfCoAXXOp1Fz6kwqwDrolNyanN9TKXRL2Rf19QKg5E1EgBUSAIWVgXubHlYxR4ydP5Z10jwedit0aMiYBVgXdyjUTvrfAwCuV9H2u3WCoORtRIAVEoCQNbHjUUbzZRdk/VS4h8t62317vy5HzJ2/C3mjlnIFH2HLVV6VvTE9eUOp+vQflTntliH00MYjKyZAKBaEnCI78WIqdp7B+gkmZOms6pyaEvvzp/7arS2pPK1Z0fCvdR+Bp2P+zZqXz2MQR2Jb8X+KgxGWCEcNc41KicBi5GrA3zeZeX5OdvMRtGz86dt+fvtZxoF1/VeL0Xi77R/X+dh9D9TdfJa9E08s0e+R08RBiMscIga6lo09EjvELgW80VcVJSReLBl2nbFnBYXPWX9KiWuY/iOURvsgaQqe7n/VLTj1kkU7dX+XZ3Hff+P4zoefS3TucJghJF61GhroOFnP/2LETYX3nI4C9bO2Gln/l0eqPwd2pzka+RFLJfo2fnzIG4/z+h4Nmw5JUD1sf2bOp37/h+214t3MgqDx2y99a3iw3Et3MR01gs68NbSoUfaf29WvTr/6kku1+dWa15IjNu/p9OtvX6rkupT0I8Jg8fssYikUnlUubCYLLrmtjbLNBf37RbrAmZ/SF+D6caoTeUWU4TBY/ZaSMIPM1tZWtuiQhJda1ujalZ9PUVrzQXDPG8cEFyGkrYL/47zkKkzEwDstZWEC9fMX9ei8+ixdx2st5hxXhFrJVyW/y9n6f84E8tbYfAhe1UBwLypWZouRRWp11kMLCya/QFz7WCBNmz/TZ2GxClqU93i2mzbbEZh8DGMzJnXjBp2Cx4EonMx577nNXrIzv/OpYsuSf6dBrwMCzIt/R/HtTXa4VtbCYOn2DsJYHHRrOVUnafXfD/s/D9GFe/cbWhW/i7HNRi1qW652+xOGDzV3kkAe40rnkindZAgsoskunb2YOd/HM8K1kRE7XaIRMHy7OW2OLG1GteW3QmD59g7CQAXuQ9aHeI67PmKZipUXpOPY2RPW0UVAeKz7ZhYE23btqnu81TJ+8LguXokAWwV9GEhsODp3BLzmlht3X4mPY7nBms1rOpdj2dhz3tgFE4t3RcGL9EjCeCCd4HgvCj599rit2C9Qfu5pD1xH/ia38d58M/HwuCleiQBYG7RVZ1z4YSz3iudnatWBi76O43368fC4DV6JQH8TbYctZ9HtZDoZXjgea0pAw/7OY0H/8TC4LV6JQGgc3D/cE1M9/S6rhZMOzmPqAzs/E/n1r9YGFxDzySAhzQ/uOcG1MAiMebvot96T1zPTD20n0/am53/eZwijoXBtfDg7jlPywPbeZ9xkcCRyEW/7d64lkhq288o7c3O/zxu/TsuDK6JzKv36I0VspZtx8LvleU4U66f0backqywQ4HOgkWyyz1ImzJN5v0wJjv/87nN9LgwuDYWX2zxnvBz8SB0FJcbHVOGcv+Cw4VGWVPCnnq2RZ66JYx2ZjGja2by4xlq538+rvG2LXUnDG6l5xnth0hGnBPKhY4oU8cPSocjrCMhabrmFESmN0ge2n9XOXANnnKMsj7m66QfFga3xMMqw4lVfAYyak8T7IuOP+MhJiMcMEVpc62OgfvBBY75UJ3pecT1yNz697gwuDXK8Jke+jxEnRPdDzclizOzzPEf4jNlHw1vOaXm+QZ5kOD12klVgafEPi4M7oES/KdPc5W1SEromNw+uA3alZsyY8cPrsfsU0N0/lsfhOSDs7/e77cYHW3nNO/jwuBethzJXIOLh8VULo5aByNqplsyj2bYbpi9XEgCtdc6iVHWP1TDNehiv+vx/G7bVh8Lg3tj1B39iBm4ZeoyTPNwE2Yd7S9ISkZYKEQyuvciSeae3TWzH0r+zvevw+v2NGGwhwwvd3kIHQXVCuZIHRnFWFDJTo+Mi/oiPGxHWARK59+rTamGuS5ge0y7WPJfB4O2tn0VC4O90LGOUv5i4SCVi9mnCfj+tMNoIxeSuewlf/Ts/A/xUHVOdX20qVv81mXF9nRhsLfs1YAWnR9zyDOcOMWImREh5f1s+/ZPwSiLhKX9Xhll6fwXVMGsBqyHjspV/uviWdy2s44LgxmMVA04ROLCaIlSODf46OcMsICP8iTfafSHFav8R/k9+JxZp1K4FmavfF3DhX7bGSW5zyIMZsKIo0KWTJmPUTMXKJ1qtvIzCRefiwVxVDOybdG8BtfPN8/HeTCwgCn7NU8l5cn3b1wPcwbuee7/kaqbI+GaHGFaL5MwmA3zZIw6oh99ZIzwSAyYj6ZisKCzojNerDFqpVPh3+Lf5m8wAuFvV191PNrc9Qid/yE6s5GSqx7s+PfBwKVtez0sDGZVpRqg7fGwHW0xEGtfRl0JznoQF199jGeWHf8+TADOFwYzq1oN0HqoboxWmh658z9ERYmKwOxTA3T8WddwVMX9406V84TBETDa8AbTITqfEXdi0FlU6PwPMerle7XftTJK/Xb8fbEupf1ddFwYHIlzawI3/ogLgPjc0fepgnuTxa+sP2m/ewVccyycZR1PtSRuRFxvLgQ8XRgcDT84C9tcHzAfFjKOuNWSazbjezC2xMOZedoKx7RSgbTTz8mtgKcLg6Ni/ocHjDdlfXT8o44qmR+vtM3yEpTJqX6MlLzR6bO+xIFGblYBThcGR8chJbONrmYxcsePzAf89MLaDe5XDpzit83w8OZ3orRPZZFrzk5/LFYBThMGq6DU6I6BGkbv+MHntyM5zZ5JAc8JFu9RkeA6s4I4PqsApwmD1fAAmb3kOir2l4/e8YOtcXYs1yEpoINe0GEvh2ctiUKLjn35b/Dnb3+5929Ef0c1WAV4XBisirIeK5IdheVX5WAZRiGe+y7tzyrA48JgdVwUjAysCuTDb1LlRDkSzhHfmChVYRXgYWFwJlYF+qPt+Q34LdrfZ1QkMV5TUl9WAR4WBmdkVWB/tDVtXu0GZStq9H0l7c8qwHFhcHZWBbazHAZTabS/4BwKE0gpF5457b2qW2FQdzhbntXGzuVejkSKhXCsym7btwpe5sODJvr+kvqqsq5obWFQMUZ4lKzZn2x14GF0hnT6HKbStmMlTF9QLYraQFIODODae1cmAFdZqgPsT44uutlQ/mY/doWz3k/B7+9vL43BKsDHwqDOx/HDHPZCdWCGToFDbThIhcNVuLFmW2nL947aRVJOVgE+FgZ1PTpE5rxZgUopfPQ1BIzu+R4kObOM8CMsXnShnzQmqwD3hUFth0oBiQGl8uXs8SwVA+bt+TzMaTPC5XPyedvvMCt+M4/zlcZlFeC+MKh+WGhIxwuy1eUM8wgj8uVM84fwQqT2f8tIfvk7s5Xvz8Vcv6N+qQarAHfCoKTb9/a7wl+qxSrAnTAozY4KiVs9pZqsAtwKg9KsLPdL9VkFuBUGpdmw9sJyvzQPTu9snwOzCYPSLJjnZ1Gkq/ulufz521/ePwLi58IswqBUHTsf6Pid55fmNfOZJgiDUlV0/BzO5It7JM1eBQiDUkW8yOmTL+34Jd2ZuQoQBqUqmOPnBD9H/JIiM1cBwqA0Oo4wZlW/i/skPWbWKkAYlEbF0cZk9NFNLkmRWasAYVAaCWV+5vdHf+OipH5mrAKEQWkEHOTBC5Es80u61oxVgDAoZcXcPq9RdjW/pLXNVgUIg1I2z1786hn9kjb1l3/OVQUIg1ImL9/8Zplf0uZ4zvBekPYZVFUYlDJx5C9pL3/71+v3j534WVRNGJSy4BCf6CaVpC3MVAUIg1IGlv4l9TBLFSAMShlY+pfUwyxVgDAo9WbpX1JPM1QBwqDUk6V/Sb3NUAUIg1JPlv4lZVC9ChAGpV4s/UvKonoVIAxKPVj6l5RN5SpAGJR6sPQvKZvKVYAwKO3N0r+krKpWAcKgtCdL/5Iyq1oFCIPSniz9S8qOKmX77BpdGJT2YulfUnZ/+scvN+8+FADi59iowqC0B0v/krKr2vkjDEp7YGFNdMNJUgaVO3+EQWkP3FjcYNGNJ0k9Ve/8EQalvZgESMpmhs4fYVDak0mApCxm6fwRBqW9mQRI6m2mzh9hUOrBJEBa1ydf/nzzzfO3N//67683f/7We+shs3X+CINSLyYBp+Fh/vzVu5tv//P25o9/9yAl3ffZ168+dPrt/fXq7W83n3/3+uZ3T+L/3axm7PwRBqWeTAKOo+N/8frd+2a632YkA3999tpzFSbGb881wPka7fXRevv+Enr609sPFYLo35rJrJ0/wqDUm0nAfbRF1PG3eLBT8v3DVz7YZ/H7L36++eKHNxefVf/sxa8fKgbRv13dzJ0/wqCUgUnAbSn3x58f7/gjVgVqY+qHKaC1OjASTK6X6G9VNHvnjzAoZTFrEnBNx99iZMg7Fyz31sA00FrXRoTrhYoClYXo71dg538rDEqZzJQEMKr74eXHi7fWwr/9l386tTIaFu1xdDaL+NrfdCvcdxUXmdr53wmDUjbVkwAestGq7a1YFRgDvw+L9Vjbcfj77Y2KQ4VthHb+94VBKaOKScDeHX+Evz9LhWUUTAGxOK/9rXqjAkElYsRthHb+HwuDUlZVkgBGdpRX2+/XEw/3J9/XnvvNjkV4p+z26G20bYR2/rEwKGU2chKQseOPMPq0KrCPa7fx9UYFKfM2Qjv/48KglN1oSQAP+RE6/tbIJd/sOKthzW18vS3bCDNtO7Xzf1gYlEYwQhJAx0+pdPSHEJ+fzurTpx47fC0W022506O3LNsI7fwfFwalUWRNAqp0/BFKvtF31uM4nKltz8pIGntsI7TzP00YlEaSKQmgVM7op/rDp/fobkSU/Nt2nAXbCPc6f8LO/3RhUBpN7yRg6fh779feC2+Ui9pBx3HuQtuOs9l6TYmd/3nCoDSiHknAbB3/ghFd1B46bs9T/LJbXlq15jZCO//zhUFpVHslAax0ZiQz6tatNTgNcDoWT7btp1trHERl53+ZMCiNbMskwI7/jtMAp2NBaNt+uu/lm98u2kZo53+5MCiNboskgA7Pjv+O0wCn87o5HW3FeolTKkx2/tcJg1IFayUBjEqcv/0Y7esBQY/jlLy27XSah7YR2vlfLwxKVVyTBNjxP442itpOd1js1rabzsP5CYfbCO381xEGpUrOTQI4qY35yPbf0cc40S5qQ91iPnu2HSJbIiGvesBWD2FQquaUJICOf4Q3sWVCuzoNcBzXXNtmUhZhUKroWBJgx38dpwGOG/EFUJpHGJSqOkwC7PjX4TRAjPK/pWplFgalyngoO8e/Htrz3L3bM2DRWttWUiZhUJLOsdeLXkby7EXdV/6qhjAoSeegs4s6wVmxMNLyv7ILg5J0DqcB7mNhZNtGUjZhUJLO5TTAHRZGtu0jZRMGJelcTgPc4gx7y/8aQRiUpHM5DXCLl0a1bSNlFAYl6RLnHLlcFW9JbNtFyigMStIlOPku6hRnQfm/bRMpqzAoSZfgxTczTwM8+f7N+2aI20bKJgxK0qVmngbgtbVte0hZhUFJutSs0wCffGn5X2MJg5J0qVmnAb74wfK/xhIGJekan339KuwkK/MFUxpNGJSka3zzfK5pgD98Zflf4wmDknSN17/+FnaUVX31b8v/Gk8YlKRrzTQN8Oqt5X+NJwxK0rVmmQb49Omr9183bgMpszAoSdeaZRrg6U9v33/duA2kzMKgJK1hhmkAEp32e0sjCIOStAYWx0WdZhUkOO13lkYRBiVpDSyOizrOKljn0H5naRRhUJLWwiK5qPMcHacdcurh4XeVRhIGJWktVacBeOlR+12lkYRBSVpL1WkAXnrUfldpJGFQktb0x7/Xmgag/P/uw+L/+PtKIwiDkrQm3pQXdaSj+ss/Lf9rfGFQktbEm/KijnRUz178+v5rxd9VGkUYlKS18ca8qDMdze+eWP5XDWFQktZWZRrgr89ev/868XeURhIGJWltVaYBfnhp+V81hEFJ2sLo0wC//+Jny/8qIwxK0haefD/2NMDn31n+Vx1hUJK28PzVu7BjHcWPP384+zf8btJowqAkbeWTL8ecBqD8334XaWRhUJK2Muo0gOV/VRMGJWkro04DWP5XNWFQkrY02jSA5X9VFAYlaUtPf3p789nXr4bBK43b7yCNLgxKkqTawqAkSaotDEqSpNrCoCRJqi0MSpKk2sKgJEmqLQxKkqTawqAkSaotDEqSpNrCoCRJqi0MSpKk2sKgJEmqLQxKkqTawqAkSaotDEqSpNrCoCRJqi0MSpKk2sKgJEmqLQxKkqTawqAkSaotDEqSpNrCoCRJqi0MSpKk2sKgJEmqLQxKkqTawqAkSaotDEqSpNrCoCRJqi0MSpKk2sKgJEmqLQxKkqTawqAkSaotDEqSpNrCoCRJqi0MSpKk2sKgJEmqLQxKkqTawqAkSaotDEqSpNrCoCRJqi0MSpKk2sKgJEmqLQxKkqTawqAkSaotDEqSpNrCoCRJqi0MSpKk2sKgJEmqLQxKkqTawqAkSaotDEqSpNrCoCRJqi0MSpKk2sKgJEmqLQxKkqTawqAkSaotDEqSpNrCoCRJqi0MSpKk2sKgJEmqLQxKkqTawqAkSaotDEqSpNrCoCRJqi0MSpKk2sKgJEmqLQxKkqTKbv7n/wPUvfsts+As/QAAAABJRU5ErkJggg==Azure Stream AnalyticsGE.PEllipsefalseAnyAnyfalseA representation of Azure Traffic Manager ( DNS-based traffic load balancer )falseSE.P.TMCore.AzureTrafficManagerCentered on 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Azure Traffic ManagerGE.PEllipsefalseAnyAnyfalseEnables execution of background processes in AzurefalseSE.P.TMCore.AzureWebJobCentered on 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Azure Web JobGE.PEllipsefalseAnyAnyfalseA representation of Dynamics CRM serverfalseSE.P.TMCore.DynamicsCRMCentered on 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Dynamics CRMGE.PEllipsefalseAnyAnyfalseA representation of Dynamics CRM PortalfalseSE.P.TMCore.DynamicsCRMPortalCentered on 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Dynamics CRM PortalGE.PEllipsefalseAnyAnyfalsefalseSelectAzure IaaSGenericHost TechnologiesVirtualDynamic97da4742-4e59-441a-994c-a1490d70dd28ListA representation of a machine e.g., on-prem or azure server that hosts an applicationfalseSE.P.TMCore.HostCentered on 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HostGE.PEllipsefalseAnyAnyfalseA representation of Identity Server falseSE.P.TMCore.IdSrvCentered on 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Identity ServerGE.PEllipsefalseAnyAnyfalsefalseSelectGenericNodeJsCSharpIoT Cloud Gateway TechnologiesVirtualDynamic9c1cc117-8938-40ca-bb0a-23d6002ddcf0ListfalseSelectAzure IoT HubAzure Event HubsAzure IoT protocol gatewayCustom cloud gatewayGateway choiceVirtualDynamic1e48cf4e-8ae0-4455-9a2b-c158693877f3ListA high-scale service enabling secure bidirectional communication from variety of devices.falseSE.GP.TMCore.IoTCloudGatewayCentered on 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 Cloud GatewayGE.PEllipsefalseAnyAnyfalseA specialized device that acts as a communication enabler between an IoT device and a cloud backendfalseSE.GP.TMCore.IoTFieldGatewayCentered on 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IoT Field GatewayGE.PEllipsefalseAnyAnyfalsefalseSelectGenericNET Framework 3WCF TechnologiesVirtualDynamicb28a8275-e02f-48b5-888c-87d03d5b01beListfalseSelectTransportMessageSecurity ModeVirtualDynamic6644d5f0-e070-4350-a13b-4d36dcb86531ListfalseSelectNonewindows username certificateClient Credential TypeVirtualDynamic18aa87e2-8648-48e7-a197-46f0b65a81d1ListfalseSelectNoneEncryptAndSign SignProtection LevelVirtualDynamicb81b55b0-ca7b-41df-8cfa-d644e1df1c92ListfalseSelectBasicHttpBindingWSHttpBinding NetTcpBinding WSFederationHttpBinding BindingVirtualDynamiccdaf2be7-2522-458a-8401-64055c7bdec3ListWindows Communication Foundation WCF is Microsoft s unified programming model for building service oriented applications. falseSE.P.TMCore.WCFCentered on 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WCFGE.PEllipsefalseAnyAnyfalsefalseSelectGenericMVC 5MVC 6Web API TechnologiesVirtualDynamic1e972c93-2bd6-4915-8f5f-f46fd9f9399dListfalseSelectOn PremAzureHosting environmentVirtualDynamic6c5d51b0-91b1-45ca-aebd-3238f93db3b8ListfalseSelectADFSAzure ADIdentity ProviderVirtualDynamic3175328a-d229-4546-887b-39b914a75dd8ListWeb APIfalseSE.P.TMCore.WebAPICentered on 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Web APIGE.PEllipsefalseAnyAnyfalsefalseSelectWeb AppWeb App for ContainersTypeVirtualDynamice8c6c66c-d75f-4ddf-bc22-3dad2a5934dbListfalseSelectTrueFalseAzure Web App Processes XMLVirtualDynamic049c845a-28c2-46f8-bda2-971ff7df9bd4ListfalseSelectTrueFalseAzure Web App Processes JSONVirtualDynamicd69db950-2372-4bd3-8328-f751f0b04c03ListfalseSelectAllow access from all networksAllow access from selected networksAzure Web App Firewall SettingsVirtualDynamic327ab565-9b38-4f6a-8171-6ab7deb2246bListfalseSelectTrueFalseAzure Web App CORS UsedVirtualDynamicf6b0309d-2020-4c3f-838f-5ab8ea0d2194ListWeb application built and hosted on Azure App ServicefalseSE.P.TMCore.AzureAppServiceWebAppCentered on stenciliVBORw0KGgoAAAANSUhEUgAAAgAAAAIACAYAAAD0eNT6AAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAABcRQAAXEUBuS1iLAAAR6FJREFUeF7t3SHYJMeRoOEFAgcMDhgYLFhgYHBgwQGDAwYHFhwwNTiw0NDggICBwYAFBgsEDAwMRBYIGhgILBAwMDAQEBAQMBAQEBAw0c33z9ZM/TnR/Vd3V2VFZH7gfR47Jc1Ud1dVRmZGRv7D999/L0mSJhM2Ssrpb9/+/ftPv/zurY//+u33v/7T12/96o9ff/+z3321q19+8u7PX/voz9+8vY4vv/n768uLr1lSTmGjpL7+8rc3Heknn7/r0H/+h789dcD//O9ffv8PH35exk9+++Xb4IGAZPk8f/zi26fPSBDTfn5J/YWNkva37uD/9T/edO7//TdfhJ3oDH760Vff/8vvv3r6Pn772ZvZBGcSpH7CRkn3Wabo6dR+8bGd/L2Y9eC7WwcHzhxI+wobJb3ss6+++/73f/n2+w9fd1J29H386NUXb2cNWFJwxkC6X9go6bnPv/77U9IbU/fV1uRHR+C1zBawxGJQIG0TNkoz++51/7FM4zPadGRfz3/79ZuggNkZgoJvvnv9ywa/tTSzsFGaCZ0D2+nY7uboflz8tgQELB0Q5K3vAWlGYaM0Ml7+dAJ0Bnb482IXwhIQtPeINIOwURoNCXuvPv3maVo46gykJY+A5Z/2/pFGFDZK1THKZ1qfrXiu4etW5BBw77DLw/wBjSpslCpinziZ+lTQi17q0r24p7i3rEWgkYSNUhVsz2Nq37V89cJSAcWJ3G6o6sJGKTNevKzV/tO/2enrXASeBKAEou19KmUXNkrZLNP7jvSVFYcgEZg6M6AqwkYpAxL5SMJyTV/VsEzAvWu9AWUWNkpnYl82JXfJxI5erlIV3MPcy2xDbe9z6Wxho9QbU/yspbqur1Fxb3OPu5NAWYSNUi+M9tlvHb0wpVFxxgR1Klwi0JnCRulIjvalNyhSxRkU7iLQGcJG6Qisgzral2Iku1qGWD2FjdKeOI6Vg1eil56k59jqyg6C9jmS9hY2So9ibZN9+07zS/f50asvnioOehaBjhI2SvdifZ9iKB7AI+2DZ+lXf7TAkPYXNkq34uXk3n3pWOTQ/OVv5gloH2GjtNXS8UcvK0nHoNKgCYN6VNgovcSOXzqfgYAeETZKl9jxS/kQCLg0oFuFjVLLjl/Kj1oCBgLaKmyUFnb8Uj0kC/Lsts+ztBY2Suw9/vBPX5vVLxVG8G4goEvCRs2LAj4UH3EfvzQO6gh4CqFaYaPmxOlkVu6TxsRsHrN6nkCoRdioubCNyFr9Y6B8LBnhEV7+VGncguNqoz8DLgvVxj3C+Rzte0DzCRs1B44gJWs4ekkoh6XTXTrvP37x7dO+7yz14ck453rA2Q9LAMHa83LtdDjRZ9O5+G08hnhuYaPGxhSgCX7nI8+ClzCjbTrNV59+87YzbX+zEXAcNAEMn5Uz8A0OcuBd4IFDcwobNS5ewK7z90Unt3TyfP/u037fOjhg9oAjcaPvUsfgHvUI4vmEjRoPGcBO9x+v7ezNvH4MsyHsSiEoME/leHzHBqjzCBs1FqaWne7fn539OZgtIN+AZQSDgmPw3bosML6wUWNg9PST3zqVugcCKDv7vLjXWcs2INgPOSouC4wtbFRtRO6W730cwRMFVOjw2+9YeZHkyjY3fjtzCR5H4GvAO6awUXXRWZlZfR9G+eRJML1s+dRxEBBT5IppbWfE7uNswJjCRtXjqP8+jvLnQ3BHkMc2xOie0GXOBowlbFQtjvq3c5SvNQJnRrbukNnO2YBxhI2qwVH/NnT6H+DDL9zipIvIHWCpgKN03TXzMmcD6gsblZ+j/uvo7KOXON+ZI39tQSIhAbYnY17mbEBtYaPyYpTCmnX0MOrNaD9qXyMznNmT9fcqXbPMDET3kz5/+m58puoJG5UTB3e4rel9TO9H7dcwfemxqLoVU95UJnQ3wfuYXTOZtpawUfkwzeZU5L6Y3m2/Z2kr8knYWuhz+RwzlAbXNYSNyoMHyUS/d1jbj9rvRWW/9juXbsUSAbNK0T02IyoymmuTX9ioHBhhONW4bV3/ESYxaS8sERBUmqD7JkHQJYHcwkadj33qs29F6vX5+Xt8UWlPzNwRWBrAf/50RkP7/SiHsFHnIZN29qIkZwQ+jFasEaAjEFzOvjxA1UVrBuQTNuocZPnPPGI4e8bjn/7tS9ctdRieb/J5Zp3ZY1mEUxvb70XnCRvVH0VHZs0m3jux7xHWCNDRZs8TMPE2j7BRfb369JvwQdE5mK5tfyNpb0ueADNP0X04Mp4xA+3zhY3qgxfAbNXFmP5kGvTfP8sd9LC/u/29pKNQXGi2GQE+72dfuSRwprBRx2OteaaqfixvUCBknQiUPTGKmZnlWqWjMSCYLRBgQEANhfa7UB9ho45FIsws6/28zFjzi6b7CIKyJ0T5clJvPCs8MzPlBBlsnyNs1HGI8KMHYESM+F9a58v+fRCgmLmsMyyBwCy7BlgaZBZk/R3oWGGj9seNzbpydOOPhql9tjy138El2ZdCGInd8nmkPbFsRjA9QyBgcmBfYaP2xQ1NIYzohh8J2cxsZ2w//0sowJP95cZns5CJzsT9N0PSMAMC63H0ETZqPzMk+9F5s4b3yPQd5UKjPzsTawQoA5akRn+nkDtkZc7jhY3aB9PGo+/xZUSyx8iY4KHCd8UUpeuUyoD8mZETBRlY3DOjqO3CRj2O/a0jP5wc97n3Hl5qpkd/VzYEPe21S2cg+B79uHACnfZzax9hox5D1Dpqwg5Tc5xU2H7mvVR5mZGU1V67dBaCcYLy6F4dgYW5jhE26n6U9oxu4BGwTn/0GniVpQC4d1nZEJyPOvPo8tv+wkbdhz270Y1b3a3b+h5FklN0HRkR8LXXL52JIH3ULccGAfsKG3W7EdfhmO5nXb79rD1U2BUAlnrO+o6ka1gWGPF4cZY63I2zj7BR2xGNEpVGN2plP//D3059yPheq7y8CAI81EQZ8RyNOBvgltx9hI3aZsTOn/XDLNPaFQoELawWqMyYpRrtkCGDgMeFjXrZiJ0/nydbtTsS7aJrzYjkRSuYKSs6y9GWKgkCrNB5v7BR143W+Wca9UcqbW9yVKLsRpsNMPC+X9ioy0br/DmjIHsEXeHY4DW+U+6T9WeQMhltNsAg4D5ho2Kjdf6V9rGzvzn6DFmRRNl+BimbkWYDDAJuFzbqfSN1/jzwFbPW6VSjz5OV1ctUATOAo5xWyrvNQ4S2Cxv13Eid/9nb+x7BdVepErigOFT7OaSMqtTeeAk5TQYB24SNemeUzp819CNr+PdSqUrgwmqBqoIlgRFKCbstd5uwUW+M0vlTUGekh6FiyWWrBaoK1tFHOFjInICXhY0ap/Pn6Fo+y/qzjaDamiUzMMxetJ9Dyoh3xggVBBn8uC33srBR3/8DHWd0Q1Uy8jnaRPbVpipdm1Q1H/+1/tHm1ua4LGycXfXIl45mhtHmJ5/XO3qZLGWnJVUJy4fVDxViNnfEmdBHhY0zq36kL9HuTB1MxWImrE1avnQO/M4E4yAPhPfLgk6Jpay1vWa1+HPaP/tXf3z3d5MQvFzXlvcFI+jqs6LW5nhf2DgrpsyjG6eKUdf7r+HzVhydOC1ZH7/fumNnG93S2Ua/eQUk/3H9dJZ8Jt6J6yCh+lZBBgzL7ycDgLfYqhXdMFXwsLafaRZMUVZcp3RasgaKZrEWzjPGb1Z9OvwRBK58/g9+Hf/zCghi2t94VmHjbIjgqya6MNXHWnj7mWZTNYBzWjIPOnruIzp6RsHVik719MGHX5RODqxUBv1IYeNMeOir3si8oCx28U7V5E2nJftjNwbr4NwzI+x5P8sPd8pZOIMFuiYPAHgJ7JV00xtTcSaSPcd0etWX+cxLOEdj/ZqXPUlwldfns/rHV3VnSmYv0BU2zoDOs+oUH+uQJpDFeNlXDepGrtvQ09LhM7PiNH4fVb9nZn8rHoy2l7BxdJVHijNm+t+KqD767ipwWvJ2dvg5VP3uue5ZZ1PDxtFV3DsOpjDbz6IYU+rRd5gdI5LZpyVfQgBM4ivr93b4ufzj69+j4g4BBoQzDqzCxpFV3evv9PDtqq73zj4tGWGUT9Iey1/Rd6Y8fvjqi6ddAtE/y4yAsr3vRhc2jqri1DCdgdPC9yFPouoIkTyG2c8N4Hll1mvmffdV8d6qOBMw20ArbBwR2+WqJYdxvU4HP6b6Nk9Gvu1nGhkFd8hzqZrIqXd+8Pq5+0Gx35F3BZUP2/tyVGHjaBgJVhtFOALcD51K9B1XwH07+o4Pglzycuz0x1MxCOA+nCXwDhtHU23d0M5/f5VrmFPzYbQEJWZmWHPldMToM2scT0FAsVm4EZ+5SNg4EtYQox84Kzv/41B2N/rOKxjh3ACW4QjEzNyfD0mB1WZ4ZijTHTaOgqzh6IfNys7/WHSgRPbRd19BxSCA5QueQxP5RBDADoHon2U1+pkBYeMIqp0QZ+ffB2t7laedq5wbwBQ/11o1AVPHqBgEjHzYWthYHaOkSiMOkmTs/PupvDMAWYMAR/vaoloQwOBs1EPXwsbqKlX6oyPyON/+Ku8MQKaqkI72datqQQBB7YhJgWFjZRTNiX7AjHhh8iC0n0F9VN4ZgDNPEORlSNEUR/u6F+++SomBVZbfbhE2VlVp3Z+bHySltZ9D/VB0Jvp9quidpMShKQRO1TK6lVO1OgGjzdaGjRVVW/dfAhU6oPazqB/um6onQy56lIomR6XS0prqIJhkMBT9s2y41pGKBIWNFVV6Of1wFfGeOY2rNxjVVt+bflQQwIin6qFKqqNSPgDPQ/ucVBU2VlNp3X/d+YOs6fbzqD9GuJWT2Lj2vc6NYFaE+9KCPeqJo4Sj9oxGGbiFjZVUWveP9p972E8ejHbb36eSR4MAtvHxYnN9X2epFASw+6V9hqoJG6uotO7/o1fxdY66v7Qqkuqi36kKgoBba0rY8SuTKjNPXGf1g7rCxio4TCT6YbK5VnmOIGb9mXS+6jsD6Mi3BAF2/MqqShBQ/byAsLECzmyOfpBsrt3IjNbaz6XzjbAzgHvr0rnmdvyq4MdFZnd77MI5StiYHS/oChHiSy9YPkP72ZRD7Z0Bb+47tlb95yoIsONXNRWeQYLtqku5YWN2Fab+uSmi9jVGme1nUx481NU7S4IAZgL+9++/KlVwRQL3b4VnsOq7PGzMrMrU/5bCFhzv2n4+5UJWffTb1WLHr7rIoapQKKjilu6wMasqU/9bRv8Ysbb0iCrVmXiZwYDqqfLer1YlMGzMqsLUP7Wto/YINdXbz6icWDuPfsNalnvTIED1/LhAEFBtVjdszKjC1P+ta1V0Ku3nVF5Vtp1Ko6owE1BpV0DYmE2Fqf97ElUMAOph32/0W0p6DO946uyvRf9e9nMD6AvYRdS+OzIKG7PJPvLauubfMgCoh2CUab7o95RmRae3dNq8r3m3gfLazN4ueH7Wz9M9/uOv3979zu2lyimvYWMmFab+770ZPQioJvbT//O/95qRyv2i0xyWDp7E5XXHflYp3I9fBwHRdWbCNbbXnU3YmAXRYr8X7X3umfpfVK4gNbsRjhCWWrxvWeZad/LtvZ8FSdTRZ8iC7YtnBUhbhY1Z/Paz3AezPNL5wwCgNrb8PHoPSGdY1tvp6BmpVj3Z7lKeQBbZt3qHjRkwwsq8zrPHtRkA1MehO9nXIzU3glTyVujs91qHz4J+4tphaxlkPvI9bMwg+4lse1SmMgAYAw+4QYCyoCztr/74ZmRfrTDNPbLnibGskjXoChvPlv0H3aumugHAOPgto99YOhKBJ6P7V59+k3q9/mgEPNH3kwXL2e01ZxA2nil74t8Pd1zzNQAYS/acFY2BEf4ynd/eg7Oi38h8hDfLMBlrA4SNZ8r8Et17mtcAYDzbM5NdMtA2DIgY4bLUNNL6/d44vTPzUhz1EdprPlvYeJbsiX97n0hlADAmMn+j31vagtEi9xBr+BlHjZllX4ojabi95jOFjWfJnPh3RPnJrOtCegyjNKsF6hY/+e2bUX7V7XiZZO5HWKZor/dMYeMZMif+7ZX012Idr/0eNIbsuSw6H50BgwCmrtv7R/ej+E7mIl2ZZn7DxjNkflketc/U44DHxotoz6RR1cbyJlX26ACc2j8WMynRb5AB/UmWXI6wsTdKTkZfVAb/98D13OxVovS4//zyu91zR1QHnT5T0qznm8DXV+ZSwSz3tNd7hrCxJx6KrJWcmEbi5Knon+3BAGAOv/n0a4OAyVCilpF+9lrwI6NvyboUQGCYYeknbOwp87Y/8hKOLDDBS6L9PjSWf/3EHQGzYBmT95nT+3lkzi1jOai93t7Cxl4yj/6XPZtHHjZhADAuRn7Zy1nrcYwwSeY1kS8v3uXRb5fB2dsCw8Zeso7+eaiX9boj6xLw9/B3aCwkIGWdetTjGLTQqWTb061Y5qWAs2cBwsYeMhf9WUpsEtVH/3wvfP7l+9AYqMme9b7WY6jtQDJf+5srP6ooRr9pBiTBt9fbS9jYQ9bDG9bZmT12J5gkNAYCWov/jIfRPtnkM5yqN7qsFTrJHWmvtZew8WhZR/887OsOmdFc9O/tybXD+hhdZM1l6WO8z06RHkf7Y+HdnvU5PWsWIGw8WtbRf1uhqUcSlyd61ZZ5r3Ff9YMAavCztm9QPq6sSwFnzQKEjUcicSb6As4W1WjuUZ3QUUZNTAlnPn70HDWDAH5Hgv8l8VdjI/Euug/OdsYsQNh4pKxffpTR22OZwgOB6iFoY7QY/Z6q8b3wbLMm7Gh/PgTvGZegz5gFCBuPwtp/9MHPFpVl7HWt0d+tnBghZk0kyiVvEEDgxr59nu/299U8si7d9Z4FCBuPknHtv038W/Q6TILM8fbvVj7MEHFka/QbKj/2gX/052+c5tcT7oOMCYG9ZwHCxiNkzfy/dDQj07zRv783OpX271YuROVO+dfEC9U8G0V6veNv1XMWIGw8QsbRf5T4t+ixBXDR/t3Kg+ni6DdTbuQaucNGL+mR6H2rnrMAYePeso7+r5Xy7Fk/2iIj+bAsdE7CqjMNjzCxT7fIuiut1yxA2Li3nqPprV6qwdyzqht7U9u/X+ehAzl3vd8g4BYsz5DUZWKf7pExsffa7PSewsY9ZUy2YDbipZdFzz3eJCe1f7/O4Xp/HUtGv+W09YiKM9R7CRv3lPHEvy1b73qeHuVWwBxc76+BlzUjfjt+7SVjP/XSLPUewsa9VB39o+co8Ge/cyvgmbhPPbs/P55dgmWn+rW3rNsCj84PCxv3kjGq2lp5L/pvj0Kw0f796oNRpCV9c7PjVw9VZ6sfETbuJVvhFCI8Ir31NUboFKL//ki+3Poj2a/nUo9ux24cnw31UHnG+l5h4x4ynrq0dfTPtEv03x+pdwnI2XF/muyXF5nZbo9Vb7yHo/vxTOyia69zL2HjHrId+kNxhS2jf5yxN/TIH1nPsesi+g10vl/Y8etk2YoDbZ25vkfY+CimLKIPcqZbRthUEIv+jCP1yPhUzoqUejPV+fGFstxSTxlnAbbOXt8qbHxUtpOWbi2teEYA4JkAxyKCzjYrped++Jv4YC6pt2yzAEeVBw4bH5ExkeLW9fUzAgD48juGmf51UIHzqOlOaauMswBHnG0RNj4i2wlLBCPtNb7krADg1kBFL2M92WN8azEIUAbZZgGoVdJe46PCxkdk+9LuWTs5KwCwIuC+SObMNhulbSiO5YyYzpRtFoA8mb2fibDxXtlOVro3e/KsAOCodZ4Zuc2vPp4HgwCdaYQB7TVh472ynap075d1VgAAX3iP+/1fvn2KlqPvV7UYBOhM2WYB9h4kho33YOtfppfuI3snzwwAzAN4TMajp/UYgwCdKVu10M++enoYwmu9Vdh4D0bb0cWeha2I7TVudWYAwIl07fVom4znemsfBgE6S7a+jfdce433ChvvkWmt5NH6yWcGAJ4MeB87//EZBOgM2ba275kMGDbeKlvy36PZ9BwSE/25PfDjugVqO74rC/zMwyBAZ8hW3I5y5u013iNsvFW2L+fRWuJnHAa0Zh7ANnT+7BmPvkONyyBAvWXLceMZaK/xHmHjrTJNj+xRU//sAGDPNZ5R0QFY3W9eJGZ5aJB6ynaOCDPv7TXeKmy8RbZjf/cYPZ8dABBQtdekd+j8M+Wc6BwGAerpzKXhyC8/eTxhPGy8RabkK14I7fXdK/rze9pzq8dIeOFb2lcLgwD1lCnfaI+BYti4FWuwmdZF9qySdHYVObcDvo8XfbY9uTqfQYB6yTbjzY619hpvETZulengn0e3/rXOHmXuleQxCjv/I90T7OYJ/GEQoF4y5bw9ugwQNm6VKQN778Q59uNHf09PvtDesPPXFtwjeyRGSdcwOxvdf2cgGHlk23jYuAWj7eiCzrL3g8/Ri9Hf09Neez0rs/PXLVi6MwjQkbL1fSxLtNe4Vdi4RabyiEdMlzO1Ev1dPTHD0l7XTHiRZ5puG90HH34xRIKlQYCONsrsd9i4RaY92Jz+1l7fozJM8+yd11AJL3CP8+3nx//25fdf/de99r8SLH89invHnTQ6SqZTArnX710GCBtfkmkK5KjSuQQV0d/X24zLAHb+/fA9RwH0v35Sv7wy74ZHpkelS+hzMs1O3nufh40vydI5grX69vr2kGW7x2yHA9n598Ms3rVEU56BTNt872EQoKNkKoF/7zJA2PiSTOsfRz3cvBijv+8Ms+wGsPPvZ2udiRF+E4MAHSFTZUCe0XtmwsPGa/hLsowKHt0C8ZIsn/PVp+MvA/Aw2fkfj2fm1rXxUXZiHJErpLll2C6+uCfIDRuvyVT8Z49ayNdkyYhmqra9tpG41a8PlsvuPUVvlPMXDAK0p0zL4fcsA4SN12Sq/X90lm+mus+MkNvrG4Gd//GYWdmj42O2bYTjlw0CtBcC40wz4u31vSRsvCbLNC2j8/ba9pYpyWPEswHs/I/H7NHewWOmQcC9ZlhWUx+ZgmJydtrruyZsvISDB6K/9Aw9OkS24EV/9xl6BDw9eaTv8Qhgj8qRyVQO9V4jBtXqL9MywK33dNh4ya/+mOeh75EZnyngwaMnP2Vh538sZul63CuZXnz3MgjQozItA9y6bTxsvCTLdG2vpDh+2OjvPws5Ce01VmPnfyyejZ7VI0eoFcBMSfu5pFtkWgbgHbu+tmvCxkimPY891+8yrVHzoq1cGpjp6EzbZkbDDN2R22IvGaFWwCP11KVMs2Hs1Guv75KwMZLp8J8e0/+LDKcCrlWessy0q2IkdL63PPRHGCGhkyDgjABK9XHfZJkJuyWYDRsjWV7evZPhMgU+uGerRwYjZI5nxPOQZYvoCMs7TOUaBOgeWQaLt/QRYWMkyxRf7xFwtkRAcBJVe52Z8ZtFn0OP4YWTrbPieqrXCuD6b1lHlZCpSN7W7YBhY4s/LPpLztD7iE9eaNF1nIkXVHudWWXaSjkKphqZmWq/60yqz/gwk2EQoFtkWgbYOlAOG1tZpsFZY2yvrYeM05o98yDulSkiHsU9tfzPUn3mh+e+ctKt+suS5Lx1O2DY2Mqy/n907f9LMo5myPhurzOTEbaHZcNDXW1UWr1WAIOOCsG2csiUM7blXRE2trKs/59VCCfjNDYjwXvWf1nOoXNmdAY6FWzprPl3ln+foJD/ni2Z/C7rm22EbWHZbJ3Sy6h6MEgQMOpZHNoXwWJ0D51hS38ZNq5lWf+nQzkr4SnTj7r20jowLy1GYMwW0GlHf8aeCEooROPIfz/c9/cc85lN9aCQa+cztJ9LamXZDrtl0BA2rmWZ0rhlb+MRMu5xbmcB+N+su5Md7gi8PtagR5p+5rNkfI624pmqkn+h82Qpmc+gr722Vti4lmX9n5Fse209Zc1q/s2nX3/PEoVFdsYy6lY0PlPlWgHMbo0wI6PjcH9E905v3KvttbXCxrUsI8mzR0JmtKuX7Amej2KmqnKtAF6s1WpxqB/u7yzLoC8tW4WNiyzr/0wbttfWGyOX6NqkPTGb0957o6peK+DsWUnllWVG9qU8sbBx4fr/c5WnLpUbM21n7XI5E4lK0fdRxUwBm7bLsnOMQKS9trWwcZGltnGWSDtLcofGMvs2s+q1Aipv0dQxsuwce+lcgLBxwUEj0R/aW5ZM6IznAqg2MnVHTPa7VfVaAWcVKVNeWXa8XOs/w0ZkWfPuffrfNZmSO1QfS1vrbZyzI+eIEUv0XVXg76m1CjvowkZk2cqQLSM6y7KIanspOWdWjFYq59qwu8EgQKiQQxc2ghKv0R/WW7btNm4H1CPcQvYyZh8r17WgGqbLOsqyi46Aur22RdiILA9gtgdp/2UAlxTuU+97Y03QcrLbVU665aVrEKAMdXTory7NSr3XsMiwFpdp/X+t8uhE56BD8GjZ27F+WTXvhoAvSwKzztHjDJYtLg083msAL6roD+kty/7/VvVtS+qLvBHXhe/H7puqZ1s46zO3LHUuWLpurw3vNYA1yugP6S1rohRTe+4G0BZuD9sHI+ks25JvRfBiEDCnLFvHP7xQq+K9BvAvR39Ib5lP3qpcy1x9kEjb3je6H4F3linVWzFg8BCh+XDPRvdDb/RX7bXhvQZk6NyuJS5k4DJAVjlmZq7tvdVjmFWJvvPseKddmorVuDJsa71UEfC9BmRIALy2dSED8iRcBlDLkV4fWfZY38PgcC5ZAtZoV8qz/wNG3dF/3FuFI1EtCqQ113r7ItCqmhzo8tA8shwMFB029uz/gBdY9B/3ViFK9mwALWY/0OcsfOdZaq7fqsIgR48jly36/XuLkuqf/R9kqXRXZSRVNTNZ+3GP/7mY2qT6XvTbZOf5AePLkggY7Uh69n+QYQcA03rtdWUVr0WaGzALT/PLgU6UzjT6jbLz/IDxZRgoRnl1z/4PMqxrE82315WVyYDzoiKkL+5cqiYH8nI2kBxXhuqx9FPtdT37P8iwZaFa8RSTAedjgZ+8qiYHMkq0dPCYslQEbJcqn10kMoxms1YAvMRkwLnwMLf3gHIhObBifg5bsHvkPzFzxXsL7Ejgnl4jc3355ya3Pi5Ldd22uN6zi+SHjv6j3qrtoyZqd91/Du7hroMp9YoVO5m9oONtP8+9+LMYVDFT+UhQxH/Ln0HAwJ/p8td2b/qI+HvtqS1E9ewi6Xij/6i3ShEnD0GGZRMdywI/dVU8Vpj7jVFj+1m2oLOhw++xM4IAi7/LWYKXZViWamcvn11ghgSaKFEhs6plSbUdD27mcyn0MkY+GZY3b7V1xom1XV7uZy578HezdOCW2FiGrartCbvPLjBDZxZtVcgqS4EHHYfO3+p+Y+B3zFDm/FbtqG2NWamMSchc057LGCPIsE2Vbcvra3p2gRnWy7hx1teUlVP/47PzHw+j04pFg9qRG8sDFSog0uEYCLxBIBd9Rz21hwI9u8AMHdqlc4uzIREmun6Nwc5/XATvFYsGsZf8T198VzKAMRDIc4LsOnnz2QVmSFKocFwmCS8V1xO1jZ3/HDLkPM2GIGbWHAECoOg76W2dsPn24ogKon+5twovXqLZ6NpVn53/XHgpZxj4zITve8bttFm2Aq53M6W7uOzlMLMUdND+WFPlOWh/c42N37xi0aDqWMqYbTYgw8wxM1/L9by9sAzTExW2AJr4N6YfvB6V2PnPi4FHhnrtsyEpbaYtthkCzfUx1G8vLEOCAiOw5XoycvQ/rg8+NABQnprtM2HgR/2A9rcYUYaddusdJW8vLENWe7tHMRtH/2NjBNj+5poPgb55Af3NcMBWhlo763727YVlKJfZ7nXNxNH/+BiJWMVMIFPavID+MvcBe8gw0F4X23t7YRnWvzLXAHD0P4cqdSh0PPMCzjFyEJBtqf3thWUoLrHOTswky/5NHY+kpHWhDMm8gP5GDQKy9CXL9by9sAw1srMWAeJmjK5XY5pxj7KuMy+gv3W2+ihYWoo+a2/LIOfthUX/Um8Zt4PwRVn1by7rNTJpYV5Af1lnhe9FjlH0OXtbdjy9vbDoX+ot4zYstqdE16qxefyvIuYF9LeuXDeC6DP2trzfni6Ijjf6l3rjWrKpePCGHjfi9KP2Y15AP8zAruvXV5dhuX0Jqp4uKEMAwPoa15JJlvUa9Ze9KJXOZ15APwzE2u+/qgw7ypY8p6cLypCZmPGF62lhcxtp1KFjmBfQD7Mu7fdfUYbD5KhHwLU8XVCGACBj4pWn/s1tlBeOjmVeQB8sBYxwUmeGXWVLvZOnC8pQnCBbGWCz/zXStKOOZ17A8UbYoZOp6u7TBWUIALLVYbf0r2BpYN2C2VTzAo6VtV7MVhkCxWcBQKYLyiLDoQ06X/WXjfojqdrdQ8epXq0zw4A7XQCQrQY7SYnRdWoubgfUPeigHEQcp3KBoAwBAMcScy1PF5QhKSFTwhVJPdE1aj7Zj6hWbr+zkNghKs8CZMq5e7qgDAEAFfe4lgwokhBdo+ZDImh7f0hbuZX4OFVnATLklz0LADJsdyMq4loy8KHV2ghbj3QOjxE/TtUdARm23S87nJ4uKEMAkKne8y8+dk+v3skUnKoO6q1H95P2U/GcgEyF954uKEMAwJfCtWRg1K41EwF1D5MAj5dt+/gWBgCBLAEAiSXR9WleFV8yOpeFxPrgO66WDJjh7B0DgAs8AEgtKwLqVtSPiO4l7a9arY4MAcCS3Px0QQYA72SYnlEuGQ+qUm4ZdlbNIlsRuZdkOn7/6YIMAN4xclekvU+kazKc+T6LjEfJX2MAEMgSALgFUBEe2vZekSJsG43uIR2HHRft75CVAUAgSwDgiV6KVHrB6FyctR7dQzpOpaJABgCBLAGAa3eKZLk/lZ91RPrjO29/h6wMAAIGAMrMAEBbWUekv5/8tk6irgFAIMsUqwGAIgYA2sL9/+fhELf1b5GVAUDAGQBlZgCgLUwAPE+VMzsyBAAWArrAAEARAwBt4Umi5+GUvfb3yChDkGgAcIEBgCIGANoiw1nvs8p0pPw1vEui6+/pWQDwL78/PwDIEr0ZAChiAKAt3AJ4ng//VOPQrnQBQIZOL8uRqwYAilgHQFvQCUX3j47Hu7v9PTIyAAhkCQAsBKQIiTvtvSK1HECcxwBgOwOAC1zDU6TKFiOdywDgPFUCgAznzTwLADJMWzHy5lrOZhavIu19IkUMAM5TJQDIMMhcjjh/uqAM095ZAgD38aq1RMvSSwwAzlMlAMiQKMrOP67l6YIMAN5hqje6Ps2rUplRncsA4Dy//KTGLoAM/e1ydsLTBWWISH71xzw/nqU8tVbpoBGdK8PLfVZZBpEvoa+Lrr+nZbbk6YIyrElkmr7xMA+tESC394gUoRhNdA/peFUKAWWYJVpqJjxdUIYAYFmTyMBpPK2RGNreI1KEgmbRPaTjkV3f/h4Z/fwP5/cvy2zJ0wVlyHzPtM7628+M4vXO3761BoC2ybDHe1ZVqnVmKL1PH8e1PF0QVc6if6mnH7364umCMnAngBaZ7kvlR7AY3Uc6XpVaHWzBi66/p6XuztMFZTqfOAPP9NaCczLa+0O65r//xndHb5UCdbYVR5+hp+XsnacLyrL1LdNUq4mAQpXMYuWR4XC12VQK1DMEiMtyyduLiv6l3j7/Ok8AwJ7S6Bo1F5aD2ntDusYDgfqrchJglsH28l57e2EZpiUyJXFYEliu/+se7gToL8tx8i9hkBtdf2/L4WZvLyzDlPeSmJCBeQDKVJtCdZgI2Bfvad7X698gqyy7RJbreXthmbYmZEEFuOg6NYdMAalqyfA+nUWmGjIvyVBzZz2z+fbCMlUnyiLDj6XzeASw7mVFwH6yDRyvyVAqmtn+5XreXliG+sTZaq7TAbgMMKdKowrl4zJAP5mSx1+SIbmcSoTL9by9sGyRSRZO5c3J6X89ynfH8f7nf51rX0WGMsDrUxPfXliG6W72Ry7XkwX1paNr1bi4D6skFSkv3x3HY/dapaW6DMn269omby8sy7a3bD8mHQFJE9G1akxVzhVXbr47+iAIqFKvI8P9sJ7dfHthWfYnZvwhLewxF87GaO8B6R6+O/ogVyv7aYAEhNG197aut5Pu4jIWdCChx2TAOWTMQ1FdJgP2RTJ7+xtkkeWQuXXS5LMLzFANMOuWjgzJGzpepS1FqiHDDquZkHyZMS8gS07IOr/p2QVmyFrNGsFlqeCk47A+t344pD04g9hfxryADMtBbaL9swvMUAwo86lObusZm6N/HeXVpxYG6i1bXkCGyrI/+e3zJc5nF5ihFkB7gZlkWcPR/hz960jcW+4IOAezyhme7QxbANdFgPDsAjOsURC1ZX4RmwswJkf/Opp1Ac7z04+++p6lmPY36SnDMlBbbv/ZBbL9KfqPesu8p5NjFF3PG4ujf/WSYZl1VjznZ23xzbLNvl0SeXaRWbasZFq3iZjVO5YqZ4mrPrLTXQo4D4M3Dmpqf5ej8Y6Jrqe3dnD97CKRYXSbeS8nzOodR7YDqDQ+dxSdj2qfPWf9siSBtp/52UUiQ6JC5p0AC48Kru+D10Hc2euCmlOGhOs6jhls9cwLyLADgJmn9rqe/R9kSHLLeChQxITA+vgNXf/XGTJ0CrOjr1mXxj1K1oH1s/+DLFMVFUZmXKPrefXxcJLc2f6+0pEIPBmFRvek+jpyFxC/c/R39hYtrT/7P8iSrMDphO21ZZTl+9JjGAl4CJB6IykwQwl2vckHOmI2MMvuuij58dn/AaPa6D/ujZmI9tqycmvPGM7KENbcmH0yCMiB2cD1YTl7YHYh+rt6iwY4z/7PgtFQ9Af0VCk72yh+LNl3oWg8BAEZ1on1ZjZwz63BWQaI0QFJz/7PgmSB6A/oiYehva7MiBozBE7aR9YTxTQu7reZg4Afvvri+//zhzw5EXsNBDL8ptEOALzXgCyFbqq9gMlbsD7AODiXYu/pQOka3nkz7i6ik1wSvykEl2Uw9ehWwSwJgJe21r/XgCx73CtWaGMNOfosqokXUZWEVI1jpjoB0VZcOt0sp68+UkI4S9Gn9gyAxXsNyHLqXdW12CwzKNqPhwWpNwLPkZcVmS19Kdmbf55lVvWed0CWBMBLg+n3GkA0luFLJwJsr62KDHkU2hfJPEdsE5IuYSQ84ruEqfWty2v8eyzHRX9Ob8xW3LI0naXY06U6J+81LDIkLhCEVH3hfvX6Cz+qhKXOw3Nh0SD1xghulKJjl6ajr6Ef4L+L/rze2PG19cTaDLvDLiUAImxElq0LPco0HsGzAsa19zYhaQtGnhxiE92TFdCnPBo80x9kCIQYnL5UM4TPGv23vTFr0V7bImxElrWLqmuvLgGM756RjPQoOpZKxcfogLaOmLcgEMry+a9VD8wyCCShtL22RdiILImA16KXrLLkUOh45Kk8sk1Iulf2QIBr27Pjb9HBZkiSvLRdOMtvc222MmxcZPhyuYb2urLzvO+5PLJNSHoUI2KmozMkyvEsMOLsFRRn2S7IgI+AZH1tWarDXvstwsZFln2YR0aRR/Cs7zm5VVBnYyTK0lTPJG4CD7Y+n5mvlWW7IKN+ArIsM+jXEgARNi6ydGTVXqxZAif1d+s2Ieko3IdU1SNxcM93EsEFHR3v5UyVMrNsF+Qa/l+SWjAvLaGHjYssU9mXyhhm5Pq/eAFUm7XSHOgkWRNmcAdG7gQHERLcln+P/4b+IPu27EzbBTPgt2u/o7WwccGXGf2hvdGhZr/xFq7/C9yzHi0snYOcnAyzAWd7aVkmbFzLUBAIVeqxE3FF1685MXvlkoDUH89d5l0SR9sycA4b17LUta9yLgBTZ9H1a14k4nigkHQOnr0MxYN6oy9qv4tW2LjG2k/0h/fGlor22rIh2nL9X5ewNlllKUsaCbMBJMRFz+WoXlr/R9i4xh7C6A8/Q6aM04jr/3oJS2rZ72NpVFmKB/WwJRE5bGxlKWiQfTug6/97GfsBNUFQOg+D2tFLtW8toBc2trIkUmxZ0ziT6/+Pmmv5xARB6TwjzwZsLaEfNrYoJhH9Jb1l3g7Iizy6Zl33j//25ZPon83ABEHpPCzH/fSj8QZuW2fLw8ZWps6NYKS9vgyyJEtWweh3+S0J6ig6Ev17s2CWzQRB6RxZSgnvZWshsrAxkmV6m46ivbYMsmyXzIqHi9+OabdL096zV/CicImHCknnGGU24JYD9MLGSJYEt6zLAFkKJmVCh0Yd8mvHUbYIEKI/ayZuF5TOU3024JYj9MPGCCOT6C87Q7ZlAF7W0XXOhLVspvUJFB+tGc6a+CxbdS5xNkA6D7MBVUsJ37LDKGy8JMtLOdsyQKbg6F4//V18IEiLtWo6eaJkOnockcnOGlaW7adnYjag/W4kHY9BzO3Lkuf3kV9+8zT6Cj9TK2y8JMt2QKZnMm2fIuMyus5K2Bvbfq6zcU0urbwOzj76yuJB0kkqHSzEu6K9/mvCxksyrc9yLe31naV6BjtT9+1nyoIofPYdAiDoZdal/X4kHe++2YD+tpT/XQsbL8lUFjhTp1V1rWiRdWvlmlUW3yDC37rFR9K+ss8G3DpTGDZek2VKNssyQKYaCfcgr+ORhL2e2E1QOTt3T+4UkM6RdTbgngPzwsZrMo3EMiwDVD8AiLyO9jNlZnLgO3wPVhGUzsG7P9NupXsShsPGazJlvGdYBqieAFixA2HWZcTynfciiMuUFCvN4mev+6DomTwDAUl7fS8JG1+SaQR2y5aHI1Q+Y7rS9H+L66bIUPS5ZsRvmSkxVhpdppw4nv/2+rYIG1+Saf3j1qzHvVWejq42/R8ZYQvmnpgVOzsolmaQ6d1z77s8bHxJpmUAKtC119dL9QTAUdaPs63FnW3ZMmiSoHScTDVKbim3vhY2bpFpK8S9H/5RdKDR9VRQefo/Url051H4PkwSlPZHMnL0zJ2BgP/ed3nYuEWm3QC3HH6wJ0ZZ0fVUMML0f4sZGYsGvY/nw2UBaT+ZTn99pDR+2LgFI67oYs5ABHRGKdvKCYAjjwxZm7NewHN8HwTtvWd9CDxYoqHYFH8/ojMmln/Gb8e/b8CirHiGMr1fHpkBDxu3yjTlekaZVPIPomvJ7pEpoyrIU6n6+xyJ7+TIJTMCy6WTfzQvg/uUP4fRFtfsVkdlkCn579Gl3LBxq0xT4PdUQXpEpi0gtzpryaQ3fiM6kOg7mB27BfY4YIiXD6N7piF7jIqo/8B7xxkCnSVT8h9bodvru0XYuBUPYXRRZ7mnEMK9KicAzrZfvMIhHmfhu7lnZE3wQB7JmVOhBDEVzrHQOOhjonvxLI/2eWHjLTJVZHskGeJWH/25bgLgGfkSZ2MK2a2CMb4XpjW3TCXyPWarwsiyxtbrlx6RKe9rj1nvsPEWmZYBGI306twyZYHegpd3+1lmwYyVJYQv44VyaUTNSCPT1GfEQEBHom85c8arRa5Ne423Chtvke1LoWNur/EITD9Gf392e9w0ldE5uCRwHUHSMrXIVH+13S4EAtY/0N54d0b321n2yOEJG2+V6QVBMNJjBFC1BDDZ8e1nmREdhLsErmOXzwcf1v2OWBKccblL+6NPyfS+2GsmN2y8VbaEOKYB22vcEzdD9Pdmxw3cfpaZ0TlUncnRNuQ3mCioR5H7Et1fZyEHrb3Ge4SN98gUHXEtR84CZCoDeYsRq//tgTyWTMtY2l+vpUGNKVP+y565bmHjPbKtjxxZ7CRbNLjVkd9JdSyNeJbA2KgJYTEh3Srb+37POi5h4z2ISKKLPQsRW3uNe8m08+EWvvyu4/thliT67jQGcncsIqRbZFsm3HMgFzbeK1u28FGZwBUPnDkyIBrNfAmCcy1/GARoq2zLvXvs/V8LG+818lTJWsW95K6B3mae2YA5cx8MArRFtkHt3gnuYeMjso2ciODaa3xUxYpyrv/fZ+zZgDk7/wVBgMtiuiTb6H/P5L9F2PiIbEVW9p4FyJbrsJUvuvuZGzAuZvN61A1RPdlG/0fs4gobH5HtgCDsOQuQ7TCILVz/34fFg8bU8wwR1cBAL9vW4CNms8PGR2XLmtxzFqDiIUCu/+/H2YAxzV4iW89lO+vlqEFc2PiobMmA2Ct6ylbvYAvX//fnbMB4Hj1aVWPIOPo/6gj3sHEPmSongVmJ9hrvUXH0Z7bzMZwNGItJgUK20T8DjaPyVMLGPRCxRB/mTHuMhKkmFv3ZWbFjof0M2pezAeM4ItFKdWTL/MeRS7hh4x6ynZ6EPdZRqpWL3WvmQ9c5GzAOArr299UcsmX+48gZ3LBxLxQtiD7QmR6dBahWA4Btme1n0HGcDajPXTNzyjj633sbeyts3AujomzJFI883Hye6M/MzATA/pj9IvDKdu9ru72OW1UdGSu8HrH1by1s3FO2hArc2yl+/nW9IkBcc/s51AdTd9m2xGqbIxOvlA99QnQfnImApL3OvYWNe8q4peLeh5vp3ejPy8oEwBy4b8gwj34j5bV33XXllW3XGnrM3oaNe8uYWHFP4Y+MOxuuYcdC+xl0DgJO7jmXBerY++Q15ZTxvd4rDyVs3FvG5ApexLcerFCtCJAVAPPhnssYECtmDs3YMu5WQ6/7Lmw8Qsa10FszLH/5Sa0A4OO/+vLKimWBaltKZ3R0FrbOlXFQR0DSXudRwsYjZEyywC3lP6sldJkAmBujj1effuOyQHK3zhSqBpJ0Mz57PXNPwsajZEy0uGWtJeP1X2ICYB10MJxIF/2OOp9bAseUcSmu9+6TsPEoWY/S3RpxZVwrusQEwHp4PlwWyMdnaTxZZ6R77zwJG4+UNeraMs0X/bdZmQBYF8sC1SpOjoxpYg8JGgcj7IzbcrnPeo7+ETYeKeOOALzUYRIgRP9dViYA1kaH47bBPHyexpF1N9cZg7aw8WhZt0FdK7tIwkj032RlAuAYCDx5MRgInMsZtTFkTfxjFvqMWaaw8WhZZwFI8rs0BZM1fyHCDd5ev2ojEKi2DXUsXzxtCSQh0OC6rqyDz7OqToaNPWT9IZgeaq8VlcoAk0jWXr/GwAjGY4fPxxoyARnJZL3XbXWfrIl/vTP/18LGHrLOAjB6jiL8SmWAqVfQXr/GwvOTNYieEc8cozhnB3LKmviHM7eZho29ZH2BRacw8SNF/25GjEza69eYCAQ8cTAXBhFsHWQ2kZlDdxCcL+vyWa+a/5eEjb1knQVAuyaTNXM0ctZ6ks5DjkrG88z1BqNPij3xbH721eVkY+0vc/5Wr5r/l4SNPWWtgEYUz3rrcp1kAUf/XkZn31Q6R6VEVb2ZaeS9whbD9btG+8k89X/26B9hY09kN2fcloF1BbBKiVfMrCzXrXlkTXIax7HvKYo/sZzDbCNBAQFd+xvrNpl3zmR4T4eNvTEtFn1BGSwJGpUSrlxznFOlRFVtxwh2ySngfURg4M6D63gH/iHx80B/0l7zGcLG3riZs9ZAJypnloIHMPrn2XgI0LwMAObCs857iWUEBlEEBjMuJZBTwYwJARLfx3JmS+azW7LM0oaNZ8g8fclNVeWQlgzrSjqHAYDWeG+BaXA6xyVIQKVZwuWauX4+B3ljfK5ra/uZT27NtEsrbDxL5mn2Koez8HC036vmYACgWzFKXgKFdbCwtuQj7GkZsa+RZ7VcxyOJe5kHa3zfzCi3z+5ZwsazUEQja0Lg0QlAe/nw9YPUfq+agwGAZvfB6/4j89T/mUV/ImHjmSptt8so2w2mfhhVRfeENIv/kXjqP+PybNh4JhICM0dw2VF5rP1ONQemVqN7QppB5s4fGbdnh41ncyrzftYinxcZ4NE9IY2OHK0PEi/TZj1OOmzMIHMWZ2buD55bdE9Io8s8a8y1Zd11ETZmkPmcgKzInG2/R83F5TPN5p+Sb9FmRrt9TrMIG7PIXMYxIwMAeUSwZvKjV7k7/+hk2UzCxiwyH+SQEftn2+9Qc3n1aZ1jq6VHsObPtr/on2XAlvbs57KEjZmQ1R59uXofB4m035/m4vOiWfwweXG2rIl/a2FjNpVO4jsT31P73WkuJBtF94Y0kuy5LsxcV0jIDhuz4aVmctPLKkScOh5LQdH9IY3gBwXKslOTo30uMwobM7LK2cuop91+b5qPeQAa1QdBWzaZDvt5SdiYFQfdRF+43uC0rPY703woBhXdH1J12QOAKlP/i7AxK05RqnIq3xky7zdVX+6e0WgyV/pbVJn6X4SNmVkm+DLPAdCC2aDoHtGtHHBkUKHzrzT1vwgbs2O7W/QDzK5a9KnjkDib92htaSzVpv4XYWN2HHriy+19fC/td6V5WUlT6qPq4CtsrMClgPcZAGjN8zSk41Wc+l+EjVXkLxDUd5ai/X4kzwaQjlN16n8RNlbBF/+T5CdB9cKSSPv9SOyccblM9dS4Z6vnXYWNlXz21Xe+4F4jEm2/GwlUiIzuGUn3G6HwWthYjVueDAB0GbMAltKW9jPKyathY0Wzbw00ANA1ltLehvPbEf0zCQTTBNXtM1ZR2FjR7KMcAwC9xFM1ryOfaJ3QxfLiR3/+5inL26BAi08+H6fgWthYFQkZ0Q82A15Q7fchrXmq5mXkEbFtsv3OWgYFcxvtxNWwsTISM6IfbnSjrEnpWATJJs2+jyWS9rvaah0U8Bx6XsmYCPgqb/mLhI2V8QPNGJkbAGgrzowwCHjniFEdsy0EWwQGH74elPB8skwX/f3Kj6BuxEJrYWN1/FCzReEGALqFSYFvkBfRfjdHIzDg+2e2kkJNLiXkN9K6/1rYOILZpjoNAHSr2ctpn9H5v4T3Fl59+s3bAMFlhXONtu6/FjaOYqb6AAYAusesNTSYlm+/iwo+//rvTwECwRsBAn7x8ZsgASZ57mvEdf+1sHEks5yIZgCge82WOMvnbb+DEbGroZ1RWCwBw8IZhveRszHKfv9LwsaRzJIUaACgR8wSBJCU1352vY88qiV4uITZo3VQcQmzLT8ulgC5dVtodWHjaIjiRs/ANQDQo5hWHjlvhs/XfmYdiwFYxSqtoyb9tcLGEY1+aJABgPbAqGe0YJl1cbY+tp9Vx6ra+VfND7lH2DiqeluftgcsBgDaC3vYSSyL7rNq6ID4POvPp+Pxnf/zv9cLJNl10X6WkYWNIxv1aFTqmLefVXoE67zcV9H9lh1JbU75n4P8gYqzSAQsI2f8R8LG0TFajm6Aynjg2s8pPYoXIhnkVbLEWeYjyHfUfw6WkCruKGCZaMRKfy8JG0fHy2G0dU4DAB2JZ4aM7swvd5YtZnyJZ1G1xDTXTI5Y+3lmEDbOgIIaIyUFGgCohyUQyFJwhoCEWh88z+21qp/KVSUfOQiqurBxFiMdisLnaD+fdCRenGdlebNey55+p/rPR0AY/UYVcO3t55lJ2DiTypFrq/1sUg9Mu/McMQV/5BIBuTsUn3GaPw/OU4h+qwoyngXRW9g4m1HqoTsaUgbL+fgk49Fp3zPLxn/HC5pnk90Is2VnZ8e7puIe/8Vs2/0uCRtnVHkaa+HISJmta9NHZk3EqoZ8i6rbQ0HgYkD5Rtg4q8rTWZilfKWkc/COqbjNb0HuiDOl74SNM2NqKLpxKvjB6wfTkqeSjlB9lpSdUqOf7nersHFmVetXr82e2SppP7wTq5eGnrXQz0vCxtkxRVSxjvUaSVROdUl6BJ1m9XchSxYzHO17j7BRY1QLJOo1sUrSPUjMrLzeD3ag8Dnaz6Y3wka9QfQ7Qslgarm3n02SLuGdEb1LKqHzNyfqurBR71Q93KLlsaiSXsKg56cf1T8szc5/m7BRzzGNPkIQ4JKApEuo5jjCe87Of7uwUe8bZSaAh4Pqau3nkzQnZgYrb39es/O/Tdio2ChBAHjgXRKQ5kZnmeVkx0fZ+d8ubNRlBAGjPDB8Dh8YaT7s7eeshui9UJGd/33CRl03yu6ABSWQnQ2Q5kAeUOVa/i07//uFjXrZaEGAswHS+NjeR4cZvQMqsvN/TNiobUYLAvDLT772pCxpMKNs71uz839c2KjtOFyieqnMFtODbheUxjDK9r41O/99hI26DevnowUB+PBPzgZIVY20vW+NYMYByj7CRt1u1CDA2QCpno/+/M0wu5XWWHL9/GtP9dtL2Kj7EASMts62IDfAs7Sl3AjWR30HMcDyHbSvsFH3G+Hs7EuYerOKoJQPHSPbeaPndgSeZXKMsFGPY/08upFHQCTuEZtSDmztGy3Jb43AxlykY4SN2gfrcNENPQpmOpySk85BFvxIBX0iDKTaz639hI3aDw/pyNE5n40RiBG61Ad7+kfM7m8xgGo/u/YVNmpfnB8wWsGgFiMR9+VKxyHI/vXrEfFIlfwifL5PPvdd0kPYqP2NWDAowsiEgKf9/JLuR4c44ra+lnv8+wobdQwi+Bmm7mAgID2OPe8/+92Y2/paDJBY3mi/Ax0nbNSxRjqG8yVk8PpQS7dhxnCm9wQJxeYR9Rc26nij7xBoGQhIL+MZGXk/f8TaIucJG9XH6DsEWiT3MKpx66D0HMtlsywPLnj3mTh8rrBR/RDxz5AcuGYgIL1BQS2q3EXPycjYNWRN//OFjeqLtS9q7UcPysgIBPjcLg1oNmT1j1qz/yXMdFjWN4ewUef4+K/fDr/H9xJeCm7/0eg4m3+2Gb816hi034nOEzbqPEyLjV7e8xpGRQRC7fciVcUMH0m/oxcDu4b1fov75BM26ly8MGbLBG7xsuSl6dYgVcU0NxnuMxTwuYag3vX+nMJG5UAHOOuSwIKRAweCmDCoKujsyG2ZaYfPJST7GsTnFTYqD7YHzbwksCAQoliI24aUEaN9AvaZ1/fX3OJXQ9ioXHi5zLZH+BqmVJkVcPeAzkYnR2A6+0zdGlP+ztjVEDYqJ9YTfdE8x8uGzGqnGdULgScB6MxJfZeY5V9L2Ki8WF+cdf/wNQRGJE5SWKX9zqRHEWASaM5yMM+tmJVzG289YaPye/WpswGXMDJjJGLmsR5Fp2ZC33UE3hb2qSlsVA3OBryMBEqmaz2aWFsxxc9ym8m31zHqN9GvtrBRtTDajR5QPcfMANuSXCZQi46Me8NOfxtH/WMIG1UPU5W+vLZj9MLUrtXJ5kSWOmv6ZvDfhqUQvrf2+1RNYaNqIlGJ6e7owdVlvNQY0fBic2vhuAiSeT7cq38fTi10e99YwkbV5mzAY1gqICDgTAJfeHUxRc1vyG9pEt/9HPWPK2xUfc4G7IdgalkucN0zN/I72CFjcuw+CJ4MgscVNmocZL/7MtwXU8gkjDG6dKvheZjpovwuwZnT+vsi6DVZdnxho8ZDZzX7qWRHIYmMAjHMuBgUHINAlmloOnsD2uNwLzOD0n7/GlPYqDExfe2yQB8GBffju6KzZ5bFynv9cN6I0/1zCRs1Nl6wvljPwVQ13z21Gyg2wzTrjMEBn5nPzhQ+3wVrzXwvbsnrj6RXC/rMKWzUHEhqc1kgD9Zdl1kDpmHpIKsGCKzPc+18Djp4Rpd8NrPx8yDY4rfxIK15hY2ax7JbwJFXDXSgdKRgXzYv8MUSMETa3/2apfNuMS2//vsW3D/LNUXXrHwogOR0v8JGzYdRJh1K9LKQNAaCNAK89vnXnMJGzYtlAbdUSWNhnd+y12qFjZKBgFQfS0Ykm7rOr0jYKC3YwsboIXq5SMqLbZRWrtQ1YaPUIgHMQEDKjy2VHmqlLcJG6RL2bbt1UMrHjl+3Chula1hPZF3RQEA6nx2/7hU2SlsYCEjnsePXo8JG6RYEAuQIUMkuelFJ2gcFu+z4tZewUboXNcWtCCfti1k2qi5avU97ChulR3F8KyOV6GUmaRtm1Zhdcx+/jhA2SnthxEKteA+BkbajLLcn9OloYaO0N0YwbCG0loAUW9b3ZzweWucIG6UjUV3wpx+ZJyCBoJjdNFbtU29ho9QDmcwsD7iNUDPiSF6n+XWmsFHqjRchL8ToRSmNgmD31affmM2vFMJG6SxMg5IrYE0BjYSkPpa+2vtdOlPYKGVAMtQvP3EHgWriOG2CWUf7yipslLJh9PTzP7hEoNyYuWKK30p9qiBslLJiiYDCKAQDbJuKXsJST2Txc/a+2/dUTdgoVUBtAWYG2DvtMoF6YqRPp0/Fy/a+lKoIG6WKPvn826ecAbcV6gis6TO970hfowgbpeo+++q7pxGalQf1CLL3TeTTqMJGaSRM01JpzbwBvYSAkVkklpaszKfRhY3SyJgdYCqX0Z0BwdxYLqIAFYmlZu5rNmGjNJNPv/zu6az1n/3O8wlGR8BH4MeMkAl8ml3YKM2MssScUWBAUB/Z+uwSYR3fDl96LmyU9A4dB2vCS1DgskFe/D78TuwIMXFPui5slHQdW8EICpalA+sQ9MX3vXT2rN+T19H+RpKuCxsl3Y4kMkaeBAUkljlbsI+ffvTV0zQ+iZvkaziyl/YRNkraDxUL6biWGQM6M2cN3iFI4vtgmybfD+v1dvTS8cJGSf3Q2S0zByBLnQ4RUYdZzfJZCHyWz8hnBsHR+ruQ1E/YKCkXitIsneYyk4BlNqFF2dqoM34ERXLWf8e6Qwdr8cs1uqdeyi9slCRJI/v+H/4/9LltVUPYeKIAAAAASUVORK5CYII=Azure App Service Web AppGE.PEllipsefalseAnyAnyfalsefalseSelectTrueFalseAzure API App Processes XMLVirtualDynamic0eb10857-97b7-4c8c-8fdd-c289b7921a7eListfalseSelectTrueFalseAzure API App Processes JSONVirtualDynamic0945adcf-1cfd-432f-8032-05391ab62336ListfalseSelectAllow access from all networksAllow access from selected networksAzure API App Firewall SettingsVirtualDynamiccb0fca77-c600-4622-b9a5-118107fcd9ddListfalseSelectTrueFalseAzure API App CORS UsedVirtualDynamic3f4a2250-9087-44c1-9fb7-61e9eb1e4df7ListWeb API built and hosted on Azure App ServicefalseSE.P.TMCore.AzureAppServiceApiAppCentered on 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Azure App Service API AppGE.PEllipsefalseAnyAnyfalsefalseSelectTrueFalseAzure Mobile App Processes XMLVirtualDynamic6c7ab607-e310-4d74-aa5b-397d87f02ee9ListfalseSelectTrueFalseAzure Mobile App Processes JSONVirtualDynamic015d94e3-d54e-4c09-9ce2-2731a0dc86f0ListfalseSelectAllow access from all networksAllow access from selected networksAzure Mobile App Firewall SettingsVirtualDynamic9b54ed83-3970-475b-97a0-be7641051497ListfalseSelectTrueFalseAzure Mobile App CORS UsedVirtualDynamic6ddbac5e-2e11-4b88-b917-587749ea4721ListMobile app backend service built and hosted on Azure App ServicefalseSE.P.TMCore.AzureAppServiceMobileAppCentered on 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Azure App Service Mobile AppGE.PEllipsefalseAnyAnyfalsefalseSelectGenericWeb FormsMVC5MVC6Web Application TechnologiesVirtualDynamicf9960f99-8659-4776-90d7-e454ef832db7ListfalseSelectOnPremAzureEnvironmentTypeVirtualDynamic80fe9520-5f00-4480-ad47-f2fd75dede82ListfalseSelectYesNoProcesses XMLVirtualDynamicdf53c172-b70c-412c-9e99-a6fbc10748eeListWeb ApplicationfalseSE.P.TMCore.WebAppCentered on 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DEIAIgQANZhixECAO7kjieMQQBAhACwDluMEABwJ3c8YQwCACIEgHXYYoQAgDu54wljEAAQIQCswxYjBADcyR1PGIMAgAgBYB22GCEA4E7ueMIYBABECADrsMUIAQB3cscTxiAAIEIAWIctRggAuJM7njAGAQARAsA6bDFCAMCd3PGEMQgAiBAA1mGLEQIA7uSOJ4xBAECEALAOW4wQAHAndzxhDAIAIgSAddhihACAO7njCWMQABAhAKzDFiMEANzJHU8YgwCACAFgHbYYIQDgTu54whgEAEQIAOuwxQgBAHdyxxPGIAAgQgBYhy1GCAC4kzueMAYBABECwDpsMUIAwJ3c8YQxCACIEADWYYsRAgDu5I4njEEAQIQAsA5bjBAAcCd3PGEMAgAiBIB12GKEAIA7ueMJYxAAECEArMMWIwQA3MkdTxiDAIAIAWAdthghAOBO7njCGAQARAgA67DFCAEAd3LHE8YgACBCAFiHLUYIALiTO54wBgEAEQLAOmwxQgDAndzxhDEIAIgQANZhixECAO7kjieMQQBAhACwDluMEABwJ3c8YQwCACIEgHXYYoQAgDu54wljEAAQIQCswxYjBADcyR1PGIMAgAgBYB22GCEA4E7ueMIYBABECADrsMUIAQB3cscTxiAAIEIAWIctRggAuJM7njAGAQARAsA6bDFCAMCd3PGEMQgAiBAA1mGLEQIA7uSOJ4xBAECEALAOW4wQAHAndzxhDAIAIgSAddhihACAO7njCWMQABAhAKzDFiMEANzJHU8YgwCACAFgHbYYIQDgTu54whgEAEQIAOuwxQgBAHdyxxPGIAAgQgBYhy1GCAC4kzueMAYBABECwDpsMUIAwJ3c8YQxCACIEADWYYsRAgDu5I4njEEAQOTf//73+08++cQePw4BYBxbjBAAcCd3PGEMAgAe9csvv7z/17/+9f7rr79+//HHH9vjSQgA49hihACAO7njCWMQAJD1008/vf/nP//5/vPPP//gmCIAjGOLEQIA7uSOJ4xBAEAL6h3QsaShAgLAOLYYIQDgTu54whgEALT2888/v/w//n9DX7YYIQDgTu54whgEAGAfthghAOBO7njCGAQAYB+2GCEA4E7ueMIYBABgH7YYIQDgTu54whgEAGAfthghAOBO7njCGASAMX788cf37969+/9++OGHP36LyH/+8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 ApplicationGE.PEllipsefalseAnyAnyfalseA representation of Azure IaaS VM Trust BoundaryfalseSE.TB.TMCore.AzureIaaSVMTrustBoundaryBefore labeliVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAOxAAADsQBlSsOGwAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAABGSURBVDhPY/hPIWBQ9Ev6z2jqDccPnr0ESxArzoDMAeEDZy+DFRIrDjeAVDCcDIDyyQajgTioAhGEQekdHx+bGIUGeP8HAJ4fIfJijo6MAAAAAElFTkSuQmCCAzure IaaS VM Trust BoundaryGE.TB.BBorderBoundaryfalseAnyAnyfalseA border representation of Azure Trust Boundary, also referred to as Azure Services ZonefalseSE.TB.TMCore.AzureTrustBoundaryBefore labeliVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAOxAAADsQBlSsOGwAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAABGSURBVDhPY/hPIWBQ9Ev6z2jqDccPnr0ESxArzoDMAeEDZy+DFRIrDjeAVDCcDIDyyQajgTioAhGEQekdHx+bGIUGeP8HAJ4fIfJijo6MAAAAAElFTkSuQmCCAzure Trust BoundaryGE.TB.BBorderBoundaryfalseAnyAnyfalseA border representation of a Cloud Gateway Zone, also referred to as Cloud Gateway Trust BoundaryfalseSE.TB.TMCore.IoTCloudGatewayZoneBefore labeliVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAOxAAADsQBlSsOGwAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAABGSURBVDhPY/hPIWBQ9Ev6z2jqDccPnr0ESxArzoDMAeEDZy+DFRIrDjeAVDCcDIDyyQajgTioAhGEQekdHx+bGIUGeP8HAJ4fIfJijo6MAAAAAElFTkSuQmCCIoT Cloud Gateway ZoneGE.TB.BBorderBoundaryfalseAnyAnyfalseA border representation of a Device Zone, also referred to as Device Trust BoundaryfalseSE.TB.TMCore.IoTDeviceZoneBefore labeliVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAOxAAADsQBlSsOGwAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAABGSURBVDhPY/hPIWBQ9Ev6z2jqDccPnr0ESxArzoDMAeEDZy+DFRIrDjeAVDCcDIDyyQajgTioAhGEQekdHx+bGIUGeP8HAJ4fIfJijo6MAAAAAElFTkSuQmCCIoT Device ZoneGE.TB.BBorderBoundaryfalseAnyAnyfalseA border representation of a Field Gateway Zone, also referred to as Field Gateway Trust BoundaryfalseSE.TB.TMCore.IoTFieldGatewayZoneBefore labeliVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAOxAAADsQBlSsOGwAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAABGSURBVDhPY/hPIWBQ9Ev6z2jqDccPnr0ESxArzoDMAeEDZy+DFRIrDjeAVDCcDIDyyQajgTioAhGEQekdHx+bGIUGeP8HAJ4fIfJijo6MAAAAAElFTkSuQmCCIoT Field Gateway ZoneGE.TB.BBorderBoundaryfalseAnyAnyfalseA border representation of a Local User Zone, also referred to as Local User Trust BoundaryfalseSE.TB.TMCore.LocalUserTrustBoundaryBefore labeliVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAOxAAADsQBlSsOGwAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAABGSURBVDhPY/hPIWBQ9Ev6z2jqDccPnr0ESxArzoDMAeEDZy+DFRIrDjeAVDCcDIDyyQajgTioAhGEQekdHx+bGIUGeP8HAJ4fIfJijo6MAAAAAElFTkSuQmCCLocal User ZoneGE.TB.BBorderBoundaryfalseAnyAnyfalseA representation of an end-users machine trust boundaryfalseSE.TB.TMCore.MachineTrustBoundaryBefore labeliVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAOxAAADsQBlSsOGwAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAABGSURBVDhPY/hPIWBQ9Ev6z2jqDccPnr0ESxArzoDMAeEDZy+DFRIrDjeAVDCcDIDyyQajgTioAhGEQekdHx+bGIUGeP8HAJ4fIfJijo6MAAAAAElFTkSuQmCCMachine Trust BoundaryGE.TB.BBorderBoundaryfalseAnyAnyfalseA border representation of a Remote User Zone, also referred to as Remote User Trust BoundaryfalseSE.TB.TMCore.RemoteUserTrustBoundaryBefore labeliVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAOxAAADsQBlSsOGwAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAABGSURBVDhPY/hPIWBQ9Ev6z2jqDccPnr0ESxArzoDMAeEDZy+DFRIrDjeAVDCcDIDyyQajgTioAhGEQekdHx+bGIUGeP8HAJ4fIfJijo6MAAAAAElFTkSuQmCCRemote User ZoneGE.TB.BBorderBoundaryfalseAnyAnyfalsefalseSelectAzureStand aloneOther cloudsEnvironmentVirtualDynamic1e5ffbf5-f5bc-4fe5-a73b-dc516d274c82ListA representation of Service Fabric Cluster for stand-alone or cloud environmentsfalseSE.TB.TMCore.ServiceFabricBefore labeliVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAOxAAADsQBlSsOGwAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAABGSURBVDhPY/hPIWBQ9Ev6z2jqDccPnr0ESxArzoDMAeEDZy+DFRIrDjeAVDCcDIDyyQajgTioAhGEQekdHx+bGIUGeP8HAJ4fIfJijo6MAAAAAElFTkSuQmCCService Fabric Trust BoundaryGE.TB.BBorderBoundaryfalseAnyAnyfalseDDenial of ServiceDenial of Service happens when the process or a datastore is not able to service incoming requests or perform up to specfalseEElevation of PrivilegesA user subject gains increased capability or privilege by taking advantage of an implementation bugfalseIInformation DisclosureInformation disclosure happens when the information can be read by an unauthorized partyfalseRRepudiationRepudiation threats involve an adversary denying that something happenedfalseSSpoofingSpoofing is when a process or entity is something other than its claimed identity. Examples include substituting a process, a file, website or a network addressfalseTTamperingTampering is the act of altering the bits. Tampering with a process involves changing bits in the running process. Similarly, Tampering with a data flow involves changing bits on the wire or between two running processestruetrueTitlefalse22222222-2222-2222-2222-2222222222220UserThreatCategoryfalse22222222-2222-2222-2222-2222222222220UserThreatShortDescriptiontrue22222222-2222-2222-2222-2222222222220UserThreatDescriptionfalse22222222-2222-2222-2222-2222222222220StateInformationfalse22222222-2222-2222-2222-2222222222220InteractionStringfalse22222222-2222-2222-2222-2222222222220PossibleMitigationsfalse22222222-2222-2222-2222-2222222222222PriorityfalseHighMediumLow22222222-2222-2222-2222-2222222222221SDLPhasefalseDesignImplementation22222222-2222-2222-2222-2222222222221falseDThe default cache that Identity Server uses is an in-memory cache that relies on a static store, available process-wide. While this works for native applications, it does not scale for mid tier and backend applications. This can cause availability issues and result in denial of service either by the influence of an adversary or by the large scale of application's users. target is 'SE.P.TMCore.IdSrv'TH112UserThreatDescriptionfalseThe default cache that Identity Server uses is an in-memory cache that relies on a static store, available process-wide. While this works for native applications, it does not scale for mid tier and backend applications. This can cause availability issues and result in denial of service either by the influence of an adversary or by the large scale of application's users. 22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseOverride the default Identity Server token cache with a scalable alternative. Refer: <a href="https://aka.ms/tmtauthn#override-token">https://aka.ms/tmtauthn#override-token</a>22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseDesign22222222-2222-2222-2222-2222222222221An adversary can leverage the weak scalability of Identity Server's token cache and cause DoSfalseDAn Adversary can launch DoS attack on WCF if Throttling in not enabledtarget is 'SE.P.TMCore.WCF'TH130UserThreatDescriptionfalseAn Adversary can launch DoS attack on WCF if Throttling in not enabled22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseEnable WCF's service throttling feature. Refer: <a href="https://aka.ms/tmtconfigmgmt#throttling">https://aka.ms/tmtconfigmgmt#throttling</a>22222222-2222-2222-2222-2222222222222PriorityfalseLow22222222-2222-2222-2222-2222222222221SDLPhasefalseImplementation22222222-2222-2222-2222-2222222222221An Adversary can launch DoS attack on WCF if Throttling in not enabledfalseDFailure to restrict requests originating from third party domains may result in unauthorized actions or access of datasource is 'SE.EI.TMCore.Browser' and target is 'SE.P.TMCore.WebApp'TH26UserThreatDescriptionfalseFailure to restrict requests originating from third party domains may result in unauthorized actions or access of data22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseEnsure that authenticated ASP.NET pages incorporate UI Redressing or clickjacking defences. Refer: <a href="https://aka.ms/tmtconfigmgmt#ui-defenses">https://aka.ms/tmtconfigmgmt#ui-defenses</a> Ensure that only trusted origins are allowed if CORS is enabled on ASP.NET Web Applications. Refer: <a href="https://aka.ms/tmtconfigmgmt#cors-aspnet">https://aka.ms/tmtconfigmgmt#cors-aspnet</a> Mitigate against Cross-Site Request Forgery (CSRF) attacks on ASP.NET web pages. Refer: <a href="https://aka.ms/tmtsmgmt#csrf-asp">https://aka.ms/tmtsmgmt#csrf-asp</a>22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseImplementation22222222-2222-2222-2222-2222222222221An adversary can perform action on behalf of other user due to lack of controls against cross domain requestsfalseDThe default cache that ADAL (Active Directory Authentication Library) uses is an in-memory cache that relies on a static store, available process-wide. While this works for native applications, it does not scale for mid tier and backend applications. This can cause availability issues and result in denial of service either by the influence of an adversary or by the large scale of application's users.target is 'SE.P.TMCore.AzureAD'TH91UserThreatDescriptionfalseThe default cache that ADAL (Active Directory Authentication Library) uses is an in-memory cache that relies on a static store, available process-wide. While this works for native applications, it does not scale for mid tier and backend applications. This can cause availability issues and result in denial of service either by the influence of an adversary or by the large scale of application's users.22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseOverride the default ADAL token cache with a scalable alternative. Refer: <a href="https://aka.ms/tmtauthn#adal-scalable">https://aka.ms/tmtauthn#adal-scalable</a>22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseDesign22222222-2222-2222-2222-2222222222221An adversary can leverage the weak scalability of token cache and cause DoSfalseEIf there is no restriction at network or host firewall level, to access the database then anyone can attempt to connect to the database from an unauthorized locationtarget is 'SE.DS.TMCore.SQL'TH1UserThreatDescriptionfalseIf there is no restriction at network or host firewall level, to access the database then anyone can attempt to connect to the database from an unauthorized location22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseConfigure a Windows Firewall for Database Engine Access. Refer: <a href="https://aka.ms/tmtconfigmgmt#firewall-db">https://aka.ms/tmtconfigmgmt#firewall-db</a>22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseImplementation22222222-2222-2222-2222-2222222222221An adversary can gain unauthorized access to database due to lack of network access protectionfalseEDue to poorly configured account policies, adversary can launch brute force attacks on {target.Name} target is 'SE.DS.TMCore.AzureSQLDB'TH10UserThreatDescriptionfalseDue to poorly configured account policies, adversary can launch brute force attacks on {target.Name} 22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseWhen possible use Azure Active Directory Authentication for connecting to SQL Database. Refer: <a href="https://aka.ms/tmt-th10a">https://aka.ms/tmt-th10a</a> Ensure that least-privileged accounts are used to connect to Database server. Refer: <a href="https://aka.ms/tmt-th10b">https://aka.ms/tmt-th10b</a> and <a href="https://aka.ms/tmt-th10c">https://aka.ms/tmt-th10c</a>22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseImplementation22222222-2222-2222-2222-2222222222221An adversary can gain unauthorized access to Azure SQL database due to weak account policyfalseEAn adversary may jail break into a mobile device and gain elevated privilegessource is 'SE.EI.TMCore.Mobile'TH104UserThreatDescriptionfalseAn adversary may jail break into a mobile device and gain elevated privileges22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseImplement implicit jailbreak or rooting detection. Refer: <a href="https://aka.ms/tmtauthz#rooting-detection">https://aka.ms/tmtauthz#rooting-detection</a>22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseDesign22222222-2222-2222-2222-2222222222221An adversary may jail break into a mobile device and gain elevated privilegesfalseEAn adversary may gain unauthorized access to Web API due to poor access control checkstarget is 'SE.P.TMCore.WebAPI'TH110UserThreatDescriptionfalseAn adversary may gain unauthorized access to Web API due to poor access control checks22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseImplement proper authorization mechanism in ASP.NET Web API. Refer: <a href="https://aka.ms/tmtauthz#authz-aspnet">https://aka.ms/tmtauthz#authz-aspnet</a>22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseImplementation22222222-2222-2222-2222-2222222222221An adversary may gain unauthorized access to Web API due to poor access control checksfalseEAn adversary can gain unauthorized access to resources in Azure subscription. The adversary can be either a disgruntled internal user, or someone who has stolen the credentials of an Azure subscription.flow.23e2b6f4-fcd8-4e76-a04a-c9ff9aff4f59 is 'No'flow crosses 'SE.TB.TMCore.AzureTrustBoundary'TH116UserThreatDescriptionfalseAn adversary can gain unauthorized access to resources in Azure subscription. The adversary can be either a disgruntled internal user, or someone who has stolen the credentials of an Azure subscription.22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseEnable fine-grained access management to Azure Subscription using RBAC. Refer: <a href="https://aka.ms/tmtauthz#grained-rbac">https://aka.ms/tmtauthz#grained-rbac</a>22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseDesign22222222-2222-2222-2222-2222222222221An adversary can gain unauthorized access to resources in an Azure subscriptionfalseEAn adversary can bypass built in security through Custom Services or ASP.NET Pages which authenticate as a service accounttarget is 'SE.P.TMCore.DynamicsCRM'TH120UserThreatDescriptionfalseAn adversary can bypass built in security through Custom Services or ASP.NET Pages which authenticate as a service account22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseCheck service account privileges and check that the custom Services or ASP.NET Pages respect CRM's security. Refer: <a href="https://aka.ms/tmtcommsec#priv-aspnet">https://aka.ms/tmtcommsec#priv-aspnet</a>22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseImplementation22222222-2222-2222-2222-2222222222221An adversary can bypass built in security through Custom Services or ASP.NET Pages which authenticate as a service accountfalseEMisconfiguration of Security Roles, Business Unit or Teamstarget is 'SE.P.TMCore.DynamicsCRM'TH124UserThreatDescriptionfalseMisconfiguration of Security Roles, Business Unit or Teams22222222-2222-2222-2222-2222222222220PossibleMitigationsfalsePerform security modelling and use Field Level Security where required. Refer: <a href="https://aka.ms/tmtauthz#modeling-field">https://aka.ms/tmtauthz#modeling-field</a> Perform security modelling and use Business Units/Teams where required. Refer: <a href="https://aka.ms/tmtdata#modeling-teams">https://aka.ms/tmtdata#modeling-teams</a>22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseDesign22222222-2222-2222-2222-2222222222221Misconfiguration of Security Roles, Business Unit or TeamsfalseEMisuse of the Share featuretarget is 'SE.P.TMCore.DynamicsCRM'TH125UserThreatDescriptionfalseMisuse of the Share feature22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseMinimize access to share feature on critical entities. Refer: <a href="https://aka.ms/tmtdata#entities">https://aka.ms/tmtdata#entities</a> Train users on the risks associated with the Dynamics CRM Share feature and good security practices. Refer: <a href="https://aka.ms/tmtdata#good-practices">https://aka.ms/tmtdata#good-practices</a>22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseImplementation22222222-2222-2222-2222-2222222222221Misuse of the Share featurefalseEUsers with CRM Portal access are inadvertently given access to sensitive records and datatarget is 'SE.P.TMCore.DynamicsCRMPortal'TH128UserThreatDescriptionfalseUsers with CRM Portal access are inadvertently given access to sensitive records and data22222222-2222-2222-2222-2222222222220PossibleMitigationsfalsePerform security modelling of portal accounts keeping in mind that the security model for the portal differs from the rest of CRM. Refer: <a href="https://aka.ms/tmtauthz#portal-security">https://aka.ms/tmtauthz#portal-security</a>22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseDesign22222222-2222-2222-2222-2222222222221Users with CRM Portal access are inadvertently given access to sensitive records and datafalseEAn adversary may gain unauthorized access to data on host machinesflow.23e2b6f4-fcd8-4e76-a04a-c9ff9aff4f59 is 'No' flow crosses 'SE.TB.TMCore.MachineTrustBoundary'TH135UserThreatDescriptionfalseAn adversary may gain unauthorized access to data on host machines22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseEnsure that proper ACLs are configured to restrict unauthorized access to data on the device. Refer: <a href="https://aka.ms/tmtauthz#acl-restricted-access">https://aka.ms/tmtauthz#acl-restricted-access</a> Ensure that sensitive user-specific application content is stored in user-profile directory. Refer: <a href="https://aka.ms/tmtauthz#sensitive-directory">https://aka.ms/tmtauthz#sensitive-directory</a>22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseImplementation22222222-2222-2222-2222-2222222222221An adversary may gain unauthorized access to data on host machinesfalseEIf an application runs under a high-privileged account, it may provide an opportunity for an adversary to gain elevated privileges and execute malicious code on host machines. E.g., If the developed executable runs under the logged-in user's identity and the user has admin rights on the machine, the executable will be running with administrator privileges. Any unnoticed vulnerability in the application could be used by adversaries to execute malicious code on the host machines that run the application.flow.23e2b6f4-fcd8-4e76-a04a-c9ff9aff4f59 is 'No'flow crosses 'SE.TB.TMCore.MachineTrustBoundary'TH136UserThreatDescriptionfalseIf an application runs under a high-privileged account, it may provide an opportunity for an adversary to gain elevated privileges and execute malicious code on host machines. E.g., If the developed executable runs under the logged-in user's identity and the user has admin rights on the machine, the executable will be running with administrator privileges. Any unnoticed vulnerability in the application could be used by adversaries to execute malicious code on the host machines that run the application.22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseEnsure that the deployed applications are run with least privileges. . Refer: <a href="https://aka.ms/tmtauthz#deployed-privileges">https://aka.ms/tmtauthz#deployed-privileges</a>22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseImplementation22222222-2222-2222-2222-2222222222221An adversary may gain elevated privileges and execute malicious code on host machinesfalseEAn adversary can gain unauthorized access to {target.Name} due to weak access control restrictionstarget is 'SE.DS.TMCore.AzureStorage'TH17UserThreatDescriptionfalseAn adversary can gain unauthorized access to {target.Name} due to weak access control restrictions22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseGrant limited access to objects in Azure Storage using SAS or SAP. It is recommended to scope SAS and SAP to permit only the necessary permissions over a short period of time. Refer: <a href="https://aka.ms/tmt-th17a">https://aka.ms/tmt-th17a</a> and <a href="https://aka.ms/tmt-th17b">https://aka.ms/tmt-th17b</a>22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseImplementation22222222-2222-2222-2222-2222222222221An adversary can gain unauthorized access to {target.Name} due to weak access control restrictionsfalseEDue to poorly configured account policies, adversary can launch brute force attacks on {target.Name}target is 'SE.DS.TMCore.SQL' and target.6047e74b-a4e1-4e5b-873e-3f7d8658d6b3 is 'OnPrem'TH2UserThreatDescriptionfalseDue to poorly configured account policies, adversary can launch brute force attacks on {target.Name}22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseWhen possible, use Windows Authentication for connecting to SQL Server. Refer: <a href="https://aka.ms/tmtauthn#win-authn-sql">https://aka.ms/tmtauthn#win-authn-sql</a> When SQL authentication mode is used, ensure that account and password policy are enforced on SQL server. Refer: <a href="https://aka.ms/tmtauthn#authn-account-pword">https://aka.ms/tmtauthn#authn-account-pword</a> Do not use SQL Authentication in contained databases. Refer: <a href="https://aka.ms/tmtauthn#autn-contained-db">https://aka.ms/tmtauthn#autn-contained-db</a>22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseImplementation22222222-2222-2222-2222-2222222222221An adversary can gain unauthorized access to SQL database due to weak account policyfalseEFailure to restrict the privileges and access rights to the application to individuals who require the privileges or access rights may result into unauthorized use of data due to inappropriate rights settings and validation.source is 'SE.EI.TMCore.Browser' and target is 'SE.P.TMCore.WebApp'TH27UserThreatDescriptionfalseFailure to restrict the privileges and access rights to the application to individuals who require the privileges or access rights may result into unauthorized use of data due to inappropriate rights settings and validation.22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseEnsure that administrative interfaces are appropriately locked down. Refer: <a href="https://aka.ms/tmtauthn#admin-interface-lockdown">https://aka.ms/tmtauthn#admin-interface-lockdown</a> Enforce sequential step order when processing business logic flows. Refer: <a href="https://aka.ms/tmtauthz#sequential-logic">https://aka.ms/tmtauthz#sequential-logic</a> Ensure that proper authorization is in place and principle of least privileges is followed. Refer: <a href="https://aka.ms/tmtauthz#principle-least-privilege">https://aka.ms/tmtauthz#principle-least-privilege</a> Business logic and resource access authorization decisions should not be based on incoming request parameters. Refer: <a href="https://aka.ms/tmtauthz#logic-request-parameters">https://aka.ms/tmtauthz#logic-request-parameters</a> Ensure that content and resources are not enumerable or accessible via forceful browsing. Refer: <a href="https://aka.ms/tmtauthz#enumerable-browsing">https://aka.ms/tmtauthz#enumerable-browsing</a>22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseImplementation22222222-2222-2222-2222-2222222222221An adversary may bypass critical steps or perform actions on behalf of other users (victims) due to improper validation logicfalseEAn adversary may gain elevated privileges on the functionality of cloud gateway if SAS tokens with over-privileged permissions are used to connect(source is 'SE.EI.TMCore.IoTdevice' or source is 'SE.GP.TMCore.IoTFieldGateway') and target is 'SE.GP.TMCore.IoTCloudGateway'TH37UserThreatDescriptionfalseAn adversary may gain elevated privileges on the functionality of cloud gateway if SAS tokens with over-privileged permissions are used to connect22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseConnect to Cloud Gateway using least-privileged tokens. Refer: <a href="https://aka.ms/tmtauthz#cloud-least-privileged">https://aka.ms/tmtauthz#cloud-least-privileged</a>22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseDesign22222222-2222-2222-2222-2222222222221An adversary may gain elevated privileges on Cloud GatewayfalseEDatabase access should be configured with roles and privilege based on least privilege and need to know principle. target is 'SE.DS.TMCore.SQL' TH4UserThreatDescriptionfalseDatabase access should be configured with roles and privilege based on least privilege and need to know principle. 22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseEnsure that least-privileged accounts are used to connect to Database server. Refer: <a href="https://aka.ms/tmtauthz#privileged-server">https://aka.ms/tmtauthz#privileged-server</a> Implement Row Level Security RLS to prevent tenants from accessing each others data. Refer: <a href="https://aka.ms/tmtauthz#rls-tenants">https://aka.ms/tmtauthz#rls-tenants</a> Sysadmin role should only have valid necessary users . Refer: <a href="https://aka.ms/tmtauthz#sysadmin-users">https://aka.ms/tmtauthz#sysadmin-users</a>22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseImplementation22222222-2222-2222-2222-2222222222221An adversary can gain unauthorized access to database due to loose authorization rulesfalseEAn adversary may get access to admin interface or privileged services like WiFi, SSH, File shares, FTP etc., on a devicesource is 'SE.EI.TMCore.IoTdevice' or source is 'SE.GP.TMCore.IoTFieldGateway'TH41UserThreatDescriptionfalseAn adversary may get access to admin interface or privileged services like WiFi, SSH, File shares, FTP etc., on a device22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseEnsure that all admin interfaces are secured with strong credentials. Refer: <a href="https://aka.ms/tmtconfigmgmt#admin-strong">https://aka.ms/tmtconfigmgmt#admin-strong</a>22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseImplementation22222222-2222-2222-2222-2222222222221An adversary may gain unauthorized access to privileged features on {source.Name}falseEAn adversary may leverage insufficient authorization checks on the device and execute unauthorized and sensitive commands remotely.(source is 'SE.GP.TMCore.IoTFieldGateway' or source is 'SE.GP.TMCore.IoTCloudGateway') and target is 'SE.EI.TMCore.IoTdevice'TH42UserThreatDescriptionfalseAn adversary may leverage insufficient authorization checks on the device and execute unauthorized and sensitive commands remotely.22222222-2222-2222-2222-2222222222220PossibleMitigationsfalsePerform authorization checks in the device if it supports various actions that require different permission levels. Refer: <a href="https://aka.ms/tmtauthz#device-permission">https://aka.ms/tmtauthz#device-permission</a>22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseDesign22222222-2222-2222-2222-2222222222221An adversary may trigger unauthorized commands on the devicefalseEAn adversary may use unused features or services on {target.Name} such as UI, USB port etc. Unused features increase the attack surface and serve as additional entry points for the adversarysource is 'SE.EI.TMCore.IoTdevice' or source is 'SE.GP.TMCore.IoTFieldGateway'TH48UserThreatDescriptionfalseAn adversary may use unused features or services on {target.Name} such as UI, USB port etc. Unused features increase the attack surface and serve as additional entry points for the adversary22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseEnsure that only the minimum services/features are enabled on devices. Refer: <a href="https://aka.ms/tmtconfigmgmt#min-enable">https://aka.ms/tmtconfigmgmt#min-enable</a>22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseImplementation22222222-2222-2222-2222-2222222222221An adversary may exploit unused services or features in {target.Name}falseEAn adversary may leverage insufficient authorization checks on the field gateway and execute unauthorized and sensitive commands remotely(source is 'SE.EI.TMCore.IoTdevice' or source is 'SE.GP.TMCore.IoTCloudGateway') and target is 'SE.GP.TMCore.IoTFieldGateway'TH51UserThreatDescriptionfalseAn adversary may leverage insufficient authorization checks on the field gateway and execute unauthorized and sensitive commands remotely22222222-2222-2222-2222-2222222222220PossibleMitigationsfalsePerform authorization checks in the Field Gateway if it supports various actions that require different permission levels. Refer: <a href="https://aka.ms/tmtauthz#field-permission">https://aka.ms/tmtauthz#field-permission</a>22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseDesign22222222-2222-2222-2222-2222222222221An adversary may trigger unauthorized commands on the field gatewayfalseEA compromised access key may permit an adversary to have over-privileged access to an {target.Name} instance target is 'SE.P.TMCore.AzureDocumentDB'TH54UserThreatDescriptionfalseA compromised access key may permit an adversary to have over-privileged access to an {target.Name} instance22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseUse resource (SAS like) tokens (derived using master keys) to connect to Cosmos DB instances whenever possible. Scope the resource tokens to permit only the privileges necessary (e.g. read-only). Store secrets in a secret storage solution (e.g. Azure Key Vault). Refer: <a href="https://aka.ms/tmt-th54">https://aka.ms/tmt-th54</a> 22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseDesign22222222-2222-2222-2222-2222222222221A compromised access key may permit an adversary to have more access than intended to an {target.Name} instance falseIAn adversary may read content stored in {target.Name} instances through SQL injection based attackstarget is 'SE.P.TMCore.AzureDocumentDB' and target.d456e645-5642-41ad-857f-951af1a3d968 is 'SQL'TH56UserThreatDescriptionfalseAn adversary may read content stored in {target.Name} instances through SQL injection based attacks22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseUse parametrized SQL queries to query Cosmos DB instances. Refer: <a href="https://aka.ms/tmt-th56">https://aka.ms/tmt-th56</a>22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseImplementation22222222-2222-2222-2222-2222222222221An adversary may read content stored in {target.Name} instances through SQL injection based attacksfalseEAn adversary can gain unauthorized access to Azure Cosmos DB instances due to weak network security configurationtarget is 'SE.P.TMCore.AzureDocumentDB' and not target.b646c6da-6894-432a-8925-646ae6d1d0ea is 'Allow access from selected networks (excluding Azure)'TH57UserThreatDescriptionfalseAn adversary can gain unauthorized access to Azure Cosmos DB instances due to weak network security configuration22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseRestrict access to Azure Cosmos DB instances by configuring account-level firewall rules to only permit connections from selected IP addresses where possible. Refer: <a href="https://aka.ms/tmt-th57">https://aka.ms/tmt-th57</a>22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseImplementation22222222-2222-2222-2222-2222222222221An adversary can gain unauthorized access to Azure Cosmos DB instances due to weak network security configurationfalseEAn adversary may leverage insufficient authorization checks on the Event Hub (SAS token) and be able to listen (Read) to the Events and manage (change) configurations of the Event Hubtarget is 'SE.P.TMCore.AzureEventHub'TH59UserThreatDescriptionfalseAn adversary may leverage insufficient authorization checks on the Event Hub (SAS token) and be able to listen (Read) to the Events and manage (change) configurations of the Event Hub22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseUse a send-only permissions SAS Key for generating device tokens. Refer: <a href="https://aka.ms/tmtauthz#sendonly-sas">https://aka.ms/tmtauthz#sendonly-sas</a>22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseDesign22222222-2222-2222-2222-2222222222221An adversary may exploit the permissions provisioned to the device token to gain elevated privilegesfalseEIf a token that grants direct access to the event hub is given to the device, it would be able to send messages directly to the eventhub without being subjected to throttling. It further exempts such a device from being able to be blacklisted.target is 'SE.P.TMCore.AzureEventHub'TH60UserThreatDescriptionfalseIf a token that grants direct access to the event hub is given to the device, it would be able to send messages directly to the eventhub without being subjected to throttling. It further exempts such a device from being able to be blacklisted.22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseDo not use access tokens that provide direct access to the Event Hub. Refer: <a href="https://aka.ms/tmtauthz#access-tokens-hub">https://aka.ms/tmtauthz#access-tokens-hub</a>22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseDesign22222222-2222-2222-2222-2222222222221An adversary bypass the secure functionalities of the Event Hub if devices authenticate with tokens that give direct access to Event HubfalseEAn adversary may gain elevated privileges on the functionality of Event Hub if SAS keys with over-privileged permissions are used to connecttarget is 'SE.P.TMCore.AzureEventHub'TH62UserThreatDescriptionfalseAn adversary may gain elevated privileges on the functionality of Event Hub if SAS keys with over-privileged permissions are used to connect22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseConnect to Event Hub using SAS keys that have the minimum permissions required. Refer: <a href="https://aka.ms/tmtauthz#sas-minimum-permissions">https://aka.ms/tmtauthz#sas-minimum-permissions</a>22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseDesign22222222-2222-2222-2222-2222222222221An adversary may gain elevated privileges on Event HubfalseEAn adversary can gain unauthorized access to all entities in {target.Name} tablestarget is 'SE.DS.TMCore.AzureStorage' and target.b3ece90f-c578-4a48-b4d4-89d97614e0d2 is 'Table'TH64UserThreatDescriptionfalseAn adversary can gain unauthorized access to all entities in {target.Name} tables22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseGrant fine-grained permission on a range of entities in Azure Table Storage. Refer: <a href="https://aka.ms/tmt-th64">https://aka.ms/tmt-th64</a>22222222-2222-2222-2222-2222222222222PriorityfalseMedium22222222-2222-2222-2222-2222222222221SDLPhasefalseImplementation22222222-2222-2222-2222-2222222222221An adversary can gain unauthorized access to all entities in {target.Name}'s tablesfalseEAn adversary can gain unauthorized access to {target.Name} instances due to weak network configurationtarget is 'SE.DS.TMCore.AzureStorage' and target.eb012c7c-9201-40d2-989f-2aad423895a5 is 'Allow access from selective networks'target is 'SE.DS.TMCore.AzureStorage'TH140UserThreatDescriptionfalseAn adversary can gain unauthorized access to {target.Name} instances due to weak network configuration22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseIt is recommended to restrict access to Azure Storage instances to selected networks where possible. <a href="https://aka.ms/tmt-th140">https://aka.ms/tmt-th140</a>22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseImplementation22222222-2222-2222-2222-2222222222221An adversary can gain unauthorized access to {target.Name} instances due to weak network configurationfalseEAn adversary may gain unauthorized access to {target.Name} account in a subscriptiontarget is 'SE.DS.TMCore.AzureStorage'TH67UserThreatDescriptionfalseAn adversary may gain unauthorized access to {target.Name} account in a subscription22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseAssign the appropriate Role-Based Access Control (RBAC) role to users, groups and applications at the right scope for the Azure Storage instance. Refer: <a href="https://aka.ms/tmt-th67">https://aka.ms/tmt-th67</a>22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseImplementation22222222-2222-2222-2222-2222222222221An adversary may gain unauthorized access to {target.Name} account in a subscriptionfalseEIf RBAC is not implemented on Service Fabric, clients may have over-privileged access on the fabric's cluster operationsflow.23e2b6f4-fcd8-4e76-a04a-c9ff9aff4f59 is 'No'flow crosses 'SE.TB.TMCore.ServiceFabric'TH71UserThreatDescriptionfalseIf RBAC is not implemented on Service Fabric, clients may have over-privileged access on the fabric's cluster operations22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseRestrict client's access to cluster operations using RBAC. Refer: <a href="https://aka.ms/tmtauthz#cluster-rbac">https://aka.ms/tmtauthz#cluster-rbac</a>22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseDesign22222222-2222-2222-2222-2222222222221An adversary may gain unauthorized access to Service Fabric cluster operationsfalseEAn adversary may gain unauthorized access to {target.Name} if connection is insecure(source is 'SE.P.TMCore.AzureDataFactory') and source.afe0080c-37dc-4d53-9edd-d0a163856bdc is 'Only Azure'(source is 'SE.P.TMCore.AzureDataFactory')TH90UserThreatDescriptionfalseAn adversary may gain unauthorized access to {target.Name} if connection is insecure22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseUse Data management gateway while connecting On Prem SQL Server to Azure Data Factory. Refer: <a href="https://aka.ms/tmtcommsec#sqlserver-factory">https://aka.ms/tmtcommsec#sqlserver-factory</a>22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseDesign22222222-2222-2222-2222-2222222222221An adversary may gain unauthorized access to {target.Name} if connection is insecurefalseIAn adversary can reverse weakly encrypted or hashed contenttarget is 'SE.P.TMCore.WebApp'TH101UserThreatDescriptionfalseAn adversary can reverse weakly encrypted or hashed content22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseDo not expose security details in error messages. Refer: <a href="https://aka.ms/tmtxmgmt#messages">https://aka.ms/tmtxmgmt#messages</a> Implement Default error handling page. Refer: <a href="https://aka.ms/tmtxmgmt#default">https://aka.ms/tmtxmgmt#default</a> Set Deployment Method to Retail in IIS. Refer: <a href="https://aka.ms/tmtxmgmt#deployment">https://aka.ms/tmtxmgmt#deployment</a> Use only approved symmetric block ciphers and key lengths. Refer: <a href="https://aka.ms/tmtcrypto#cipher-length">https://aka.ms/tmtcrypto#cipher-length</a> Use approved block cipher modes and initialization vectors for symmetric ciphers. Refer: <a href="https://aka.ms/tmtcrypto#vector-ciphers">https://aka.ms/tmtcrypto#vector-ciphers</a> Use approved asymmetric algorithms, key lengths, and padding. Refer: <a href="https://aka.ms/tmtcrypto#padding">https://aka.ms/tmtcrypto#padding</a> Use approved random number generators. Refer: <a href="https://aka.ms/tmtcrypto#numgen">https://aka.ms/tmtcrypto#numgen</a> Do not use symmetric stream ciphers. Refer: <a href="https://aka.ms/tmtcrypto#stream-ciphers">https://aka.ms/tmtcrypto#stream-ciphers</a> Use approved MAC/HMAC/keyed hash algorithms. Refer: <a href="https://aka.ms/tmtcrypto#mac-hash">https://aka.ms/tmtcrypto#mac-hash</a> Use only approved cryptographic hash functions. Refer: <a href="https://aka.ms/tmtcrypto#hash-functions">https://aka.ms/tmtcrypto#hash-functions</a> Verify X.509 certificates used to authenticate SSL, TLS, and DTLS connections. Refer: <a href="https://aka.ms/tmtcommsec#x509-ssltls">https://aka.ms/tmtcommsec#x509-ssltls</a>22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseImplementation22222222-2222-2222-2222-2222222222221An adversary can reverse weakly encrypted or hashed contentfalseIAn adversary may gain access to sensitive data from log filestarget is 'SE.P.TMCore.WebApp' TH102UserThreatDescriptionfalseAn adversary may gain access to sensitive data from log files22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseEnsure that the application does not log sensitive user data. Refer: <a href="https://aka.ms/tmtauditlog#log-sensitive-data">https://aka.ms/tmtauditlog#log-sensitive-data</a> Ensure that Audit and Log Files have Restricted Access. Refer: <a href="https://aka.ms/tmtauditlog#log-restricted-access">https://aka.ms/tmtauditlog#log-restricted-access</a>22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseImplementation22222222-2222-2222-2222-2222222222221An adversary may gain access to sensitive data from log filesfalseIAn adversary may gain access to unmasked sensitive data such as credit card numberssource is 'SE.EI.TMCore.Browser' and target is 'SE.P.TMCore.WebApp'TH103UserThreatDescriptionfalseAn adversary may gain access to unmasked sensitive data such as credit card numbers22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseEnsure that sensitive data displayed on the user screen is masked. Refer: <a href="https://aka.ms/tmtdata#data-mask">https://aka.ms/tmtdata#data-mask</a>22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseImplementation22222222-2222-2222-2222-2222222222221An adversary may gain access to unmasked sensitive data such as credit card numbersfalseIAn adversary can gain access to sensitive data such as the following, through verbose error messages - Server names - Connection strings - Usernames - Passwords - SQL procedures - Details of dynamic SQL failures - Stack trace and lines of code - Variables stored in memory - Drive and folder locations - Application install points - Host configuration settings - Other internal application details target is 'SE.P.TMCore.WebAPI'TH106UserThreatDescriptionfalseAn adversary can gain access to sensitive data such as the following, through verbose error messages - Server names - Connection strings - Usernames - Passwords - SQL procedures - Details of dynamic SQL failures - Stack trace and lines of code - Variables stored in memory - Drive and folder locations - Application install points - Host configuration settings - Other internal application details 22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseEnsure that proper exception handling is done in ASP.NET Web API. Refer: <a href="https://aka.ms/tmtxmgmt#exception">https://aka.ms/tmtxmgmt#exception</a>22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseImplementation22222222-2222-2222-2222-2222222222221An adversary can gain access to sensitive information from an API through error messagesfalseIAn adversary may retrieve sensitive data (e.g, auth tokens) persisted in browser storagesource is 'SE.EI.TMCore.Browser' and target is 'SE.P.TMCore.WebAPI' TH107UserThreatDescriptionfalseAn adversary may retrieve sensitive data (e.g, auth tokens) persisted in browser storage22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseEnsure that sensitive data relevant to Web API is not stored in browser's storage. Refer: <a href="https://aka.ms/tmtdata#api-browser">https://aka.ms/tmtdata#api-browser</a>22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseImplementation22222222-2222-2222-2222-2222222222221An adversary may retrieve sensitive data (e.g, auth tokens) persisted in browser storagefalseIAn adversary may sniff the data sent from Identity Server. This can lead to a compromise of the tokens issued by the Identity Servertarget is 'SE.P.TMCore.IdSrv'TH115UserThreatDescriptionfalseAn adversary may sniff the data sent from Identity Server. This can lead to a compromise of the tokens issued by the Identity Server22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseEnsure that all traffic to Identity Server is over HTTPS connection. Refer: <a href="https://aka.ms/tmtcommsec#identity-https">https://aka.ms/tmtcommsec#identity-https</a>22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseDesign22222222-2222-2222-2222-2222222222221An adversary may sniff the data sent from Identity ServerfalseISensitive attributes or fields on an Entity can be inadvertently disclosedtarget is 'SE.P.TMCore.DynamicsCRM'TH119UserThreatDescriptionfalseSensitive attributes or fields on an Entity can be inadvertently disclosed22222222-2222-2222-2222-2222222222220PossibleMitigationsfalsePerform security modelling and use Field Level Security where required. Refer: <a href="https://aka.ms/tmtauthz#modeling-field">https://aka.ms/tmtauthz#modeling-field</a> Perform security modelling and use Business Units/Teams where required. Refer: <a href="https://aka.ms/tmtdata#modeling-teams">https://aka.ms/tmtdata#modeling-teams</a>22222222-2222-2222-2222-2222222222222PriorityfalseMedium22222222-2222-2222-2222-2222222222221SDLPhasefalseDesign22222222-2222-2222-2222-2222222222221Sensitive attributes or fields on an Entity can be inadvertently disclosedfalseISensitive Entity records (containing PII, HBI information) can be inadvertently disclosed to users who should not have accesstarget is 'SE.P.TMCore.DynamicsCRM'TH121UserThreatDescriptionfalseSensitive Entity records (containing PII, HBI information) can be inadvertently disclosed to users who should not have access22222222-2222-2222-2222-2222222222220PossibleMitigationsfalsePerform security modelling and use Field Level Security where required. Refer: <a href="https://aka.ms/tmtauthz#modeling-field">https://aka.ms/tmtauthz#modeling-field</a> Perform security modelling and use Business Units/Teams where required. Refer: <a href="https://aka.ms/tmtdata#modeling-teams">https://aka.ms/tmtdata#modeling-teams</a>22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseDesign22222222-2222-2222-2222-2222222222221Sensitive Entity records (containing PII, HBI information) can be inadvertently disclosed to users who should not have accessfalseIIf a mobile device containing cached customer data in the CRM Mobile Client is lost the data could be disclosed if the device is not securedtarget is 'SE.EI.TMCore.DynamicsCRMMobileClient'TH122UserThreatDescriptionfalseIf a mobile device containing cached customer data in the CRM Mobile Client is lost the data could be disclosed if the device is not secured22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseEnsure a device management policy is in place that requires a use PIN and allows remote wiping. Refer: <a href="https://aka.ms/tmtcrypto#pin-remote">https://aka.ms/tmtcrypto#pin-remote</a>22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseDesign22222222-2222-2222-2222-2222222222221If a mobile device containing cached customer data in the CRM Mobile Client is lost the data could be disclosed if the device is not securedfalseIIf a laptop with the Dynamics CRM Outlook Client and offline data is lost the data could be disclosed if the device is not securedtarget is 'SE.EI.TMCore.DynamicsCRMOutlookClient'TH123UserThreatDescriptionfalseIf a laptop with the Dynamics CRM Outlook Client and offline data is lost the data could be disclosed if the device is not secured22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseEnsure a device management policy is in place that requires a PIN/password/auto lock and encrypts all data (e.g. Bitlocker). Refer: <a href="https://aka.ms/tmtcrypto#bitlocker">https://aka.ms/tmtcrypto#bitlocker</a>22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseDesign22222222-2222-2222-2222-2222222222221If a laptop with the Dynamics CRM Outlook Client and offline data is lost the data could be disclosed if the device is not securedfalseISecure system configuration information exposed via JScripttarget is 'SE.P.TMCore.DynamicsCRM'TH126UserThreatDescriptionfalseSecure system configuration information exposed via JScript22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseInclude a development standards rule proscribing showing config details in exception management outside development. Refer: <a href="https://aka.ms/tmtdata#exception-mgmt">https://aka.ms/tmtdata#exception-mgmt</a>22222222-2222-2222-2222-2222222222222PriorityfalseMedium22222222-2222-2222-2222-2222222222221SDLPhasefalseImplementation22222222-2222-2222-2222-2222222222221Secure system configuration information exposed via JScriptfalseISecure system configuration information exposed when exception is thrown.target is 'SE.P.TMCore.DynamicsCRM'TH127UserThreatDescriptionfalseSecure system configuration information exposed when exception is thrown.22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseInclude a development standards rule proscribing showing config details in exception management outside development. Refer: <a href="https://aka.ms/tmtdata#exception-mgmt">https://aka.ms/tmtdata#exception-mgmt</a>22222222-2222-2222-2222-2222222222222PriorityfalseMedium22222222-2222-2222-2222-2222222222221SDLPhasefalseImplementation22222222-2222-2222-2222-2222222222221Secure system configuration information exposed when a DotNET exception is thrownfalseIAn Adversary can sniff communication channel and steal the secrets.target is 'SE.P.TMCore.WCF'TH131UserThreatDescriptionfalseAn Adversary can sniff communication channel and steal the secrets.22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseEnable HTTPS - Secure Transport channel. Refer: <a href="https://aka.ms/tmtcommsec#https-transport">https://aka.ms/tmtcommsec#https-transport</a>22222222-2222-2222-2222-2222222222222PriorityfalseMedium22222222-2222-2222-2222-2222222222221SDLPhasefalseImplementation22222222-2222-2222-2222-2222222222221An Adversary can sniff communication channel and steal the secrets falseIAn adversary may gain access to sensitive data stored on host machinesflow.23e2b6f4-fcd8-4e76-a04a-c9ff9aff4f59 is 'No' flow crosses 'SE.TB.TMCore.MachineTrustBoundary'TH139UserThreatDescriptionfalseAn adversary may gain access to sensitive data stored on host machines22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseConsider using Encrypted File System (EFS) is used to protect confidential user-specific data. Refer: <a href="https://aka.ms/tmtdata#efs-user">https://aka.ms/tmtdata#efs-user</a> Ensure that sensitive data stored by the application on the file system is encrypted. Refer: <a href="https://aka.ms/tmtdata#filesystem">https://aka.ms/tmtdata#filesystem</a>22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseDesign22222222-2222-2222-2222-2222222222221An adversary may gain access to sensitive data stored on host machinesfalseIAn adversary can read sensitive data by sniffing traffic to {target.Name}target is 'SE.P.TMCore.AzureRedis' and not target.866e2e37-a089-45bc-9576-20fc95304b82 is 'True'TH14UserThreatDescriptionfalseAn adversary can read sensitive data by sniffing traffic to {target.Name}22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseEnsure that communication to {target.Name} is over SSL/TLS. Configure {target.Name} such that only connections over SSL/TLS are permitted. Also ensure that connection string(s) used by clients have the ssl flag set to true (I.e. ssl=true). Refer: <a href="https://aka.ms/tmt-th14">https://aka.ms/tmt-th14</a>.22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseImplementation22222222-2222-2222-2222-2222222222221An adversary can read sensitive data by sniffing traffic to {target.Name}falseIAn adversary can gain access to sensitive data by sniffing traffic from Mobile clientsource is 'SE.EI.TMCore.Mobile'TH15UserThreatDescriptionfalseAn adversary can gain access to sensitive data by sniffing traffic from Mobile client22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseImplement Certificate Pinning. Refer: <a href="https://aka.ms/tmtcommsec#cert-pinning">https://aka.ms/tmtcommsec#cert-pinning</a>22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseImplementation22222222-2222-2222-2222-2222222222221An adversary can gain access to sensitive data by sniffing traffic from Mobile clientfalseIAn adversary can gain access to sensitive data by sniffing traffic to Web APItarget is 'SE.P.TMCore.WebAPI'TH16UserThreatDescriptionfalseAn adversary can gain access to sensitive data by sniffing traffic to Web API22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseForce all traffic to Web APIs over HTTPS connection. Refer: <a href="https://aka.ms/tmtcommsec#webapi-https">https://aka.ms/tmtcommsec#webapi-https</a>22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseImplementation22222222-2222-2222-2222-2222222222221An adversary can gain access to sensitive data by sniffing traffic to Web APIfalseIAn adversary can read sensitive data by sniffing unencrypted SMB traffic to {target.Name}target is 'SE.DS.TMCore.AzureStorage' and target.b3ece90f-c578-4a48-b4d4-89d97614e0d2 is 'File'TH19UserThreatDescriptionfalseAn adversary can read sensitive data by sniffing unencrypted SMB traffic to {target.Name}22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseUse SMB 3.0 compatible client to ensure in-transit data encryption to Azure File Shares. Refer: <a href="https://aka.ms/tmt-th19a">https://aka.ms/tmt-th19a</a> and <a href="https://aka.ms/tmt-th19b">https://aka.ms/tmt-th19b</a>22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseImplementation22222222-2222-2222-2222-2222222222221An adversary can read sensitive data by sniffing unencrypted SMB traffic to {target.Name}falseIIf application saves sensitive PII or HBI data on phone SD card or local storage, then it ay get stolen.source is 'SE.EI.TMCore.Mobile'TH31UserThreatDescriptionfalseIf application saves sensitive PII or HBI data on phone SD card or local storage, then it ay get stolen.22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseEncrypt sensitive or PII data written to phones local storage. Refer: <a href="https://aka.ms/tmtdata#pii-phones">https://aka.ms/tmtdata#pii-phones</a>22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseImplementation22222222-2222-2222-2222-2222222222221An adversary can gain sensitive data from mobile devicefalseIAn adversary may eavesdrop and interfere with the communication between {source.Name} and {target.Name} and possibly tamper the data that is transmitted.(source is 'SE.EI.TMCore.IoTdevice' or source is 'SE.GP.TMCore.IoTFieldGateway') and target is 'SE.GP.TMCore.IoTCloudGateway'TH38UserThreatDescriptionfalseAn adversary may eavesdrop and interfere with the communication between {source.Name} and {target.Name} and possibly tamper the data that is transmitted.22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseSecure Device to Cloud Gateway communication using SSL/TLS. Refer: <a href="https://aka.ms/tmtcommsec#device-cloud">https://aka.ms/tmtcommsec#device-cloud</a>22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseDesign22222222-2222-2222-2222-2222222222221An adversary may eavesdrop the traffic to cloud gatewayfalseIAn adversary can eaves drop on communication between application server and {target.Name} server, due to clear text communication protocol usage.(target is 'SE.DS.TMCore.SQL' and source is 'SE.P.TMCore.WebApp')TH5UserThreatDescriptionfalseAn adversary can eaves drop on communication between application server and {target.Name} server, due to clear text communication protocol usage.22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseEnsure SQL server connection encryption and certificate validation. Refer: <a href="https://aka.ms/tmtcommsec#sqlserver-validation">https://aka.ms/tmtcommsec#sqlserver-validation</a> Force Encrypted communication to SQL server. Refer: <a href="https://aka.ms/tmtcommsec#encrypted-sqlserver">https://aka.ms/tmtcommsec#encrypted-sqlserver</a>22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseImplementation22222222-2222-2222-2222-2222222222221An adversary can gain access to sensitive data by sniffing traffic to databasefalseIAn adversary may eavesdrop and interfere with the communication between the device and the field gateway and possibly tamper the data that is transmittedsource is 'SE.EI.TMCore.IoTdevice' and target is 'SE.GP.TMCore.IoTFieldGateway'TH52UserThreatDescriptionfalseAn adversary may eavesdrop and interfere with the communication between the device and the field gateway and possibly tamper the data that is transmitted22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseSecure Device to Field Gateway communication. Refer: <a href="https://aka.ms/tmtcommsec#device-field">https://aka.ms/tmtcommsec#device-field</a>22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseDesign22222222-2222-2222-2222-2222222222221An adversary may eavesdrop the communication between the device and the field gatewayfalseIAn adversary having access to {target.Name} may read sensitive clear-text datatarget is 'SE.P.TMCore.AzureDocumentDB'TH53UserThreatDescriptionfalseAn adversary having access to {target.Name} may read sensitive clear-text data22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseEncrypt sensitive data before storing it in Azure Document DB.22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseDesign22222222-2222-2222-2222-2222222222221An adversary having access to {target.Name} may read sensitive clear-text datafalseIAdditional controls like Transparent Data Encryption, Column Level Encryption, EKM etc. provide additional protection mechanism to high value PII or HBI data. target is 'SE.DS.TMCore.SQL'TH6UserThreatDescriptionfalseAdditional controls like Transparent Data Encryption, Column Level Encryption, EKM etc. provide additional protection mechanism to high value PII or HBI data. 22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseUse strong encryption algorithms to encrypt data in the database. Refer: <a href="https://aka.ms/tmtcrypto#strong-db">https://aka.ms/tmtcrypto#strong-db</a> Ensure that sensitive data in database columns is encrypted. Refer: <a href="https://aka.ms/tmtdata#db-encrypted">https://aka.ms/tmtdata#db-encrypted</a> Ensure that database-level encryption (TDE) is enabled. Refer: <a href="https://aka.ms/tmtdata#tde-enabled">https://aka.ms/tmtdata#tde-enabled</a> Ensure that database backups are encrypted. Refer: <a href="https://aka.ms/tmtdata#backup">https://aka.ms/tmtdata#backup</a> Use SQL server EKM to protect encryption keys. Refer: <a href="https://aka.ms/tmtcrypto#ekm-keys">https://aka.ms/tmtcrypto#ekm-keys</a> Use AlwaysEncrypted feature if encryption keys should not be revealed to Database engine. Refer: <a href="https://aka.ms/tmtcrypto#keys-engine">https://aka.ms/tmtcrypto#keys-engine</a>22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseImplementation22222222-2222-2222-2222-2222222222221An adversary can gain access to sensitive PII or HBI data in databasefalseEAn adversary can abuse poorly managed {target.Name} account access keys and gain unauthorized access to storage.target is 'SE.DS.TMCore.AzureStorage'TH63UserThreatDescriptionfalseAn adversary can abuse poorly managed {target.Name} account access keys and gain unauthorized access to storage.22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseEnsure secure management and storage of Azure storage access keys. It is recommended to rotate storage access keys regularly, in accordance with organizational policies. Refer: <a href="https://aka.ms/tmt-th63">https://aka.ms/tmt-th63</a>22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseImplementation22222222-2222-2222-2222-2222222222221An adversary can abuse poorly managed {target.Name} account access keysfalseIAn adversary can abuse an insecure communication channel between a client and {target.Name}target is 'SE.DS.TMCore.AzureStorage' and target.229f2e53-bc3f-476c-8ac9-57da37efd00f is 'True'target is 'SE.DS.TMCore.AzureStorage'TH65UserThreatDescriptionfalseAn adversary can abuse an insecure communication channel between a client and {target.Name}22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseEnsure that communication to Azure Storage is over HTTPS. It is recommended to enable the secure transfer required option to force communication with Azure Storage to be over HTTPS. Use Client-Side Encryption to store sensitive data in Azure Storage. Refer: <a href="https://aka.ms/tmt-th65">https://aka.ms/tmt-th65</a>22222222-2222-2222-2222-2222222222222PriorityfalseMedium22222222-2222-2222-2222-2222222222221SDLPhasefalseImplementation22222222-2222-2222-2222-2222222222221An adversary can abuse an insecure communication channel between a client and {target.Name}falseISecrets can be any sensitive information, such as storage connection strings, passwords, or other values that should not be handled in plain text. If secrets are not encrypted, an adversary who can gain access to them can abuse them.flow.23e2b6f4-fcd8-4e76-a04a-c9ff9aff4f59 is 'No' flow crosses 'SE.TB.TMCore.ServiceFabric'TH73UserThreatDescriptionfalseSecrets can be any sensitive information, such as storage connection strings, passwords, or other values that should not be handled in plain text. If secrets are not encrypted, an adversary who can gain access to them can abuse them.22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseEncrypt secrets in Service Fabric applications. Refer: <a href="https://aka.ms/tmtdata#fabric-apps">https://aka.ms/tmtdata#fabric-apps</a>22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseImplementation22222222-2222-2222-2222-2222222222221An adversary can gain access to unencrypted secrets in Service Fabric applicationsfalseIAn adversary may conduct man in the middle attack and downgrade TLS connection to clear text protocol, or forcing browser communication to pass through a proxy server that he controls. This may happen because the application may use mixed content or HTTP Strict Transport Security policy is not ensured. source is 'GE.EI' and target is 'SE.P.TMCore.WebApp' and target.80fe9520-5f00-4480-ad47-f2fd75dede82 is 'Azure' TH78UserThreatDescriptionfalseAn adversary may conduct man in the middle attack and downgrade TLS connection to clear text protocol, or forcing browser communication to pass through a proxy server that he controls. This may happen because the application may use mixed content or HTTP Strict Transport Security policy is not ensured. 22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseConfigure SSL certificate for custom domain in Azure App Service. Refer: <a href="https://aka.ms/tmtcommsec#ssl-appservice">https://aka.ms/tmtcommsec#ssl-appservice</a> Force all traffic to Azure App Service over HTTPS connection . Refer: <a href="https://aka.ms/tmtcommsec#appservice-https">https://aka.ms/tmtcommsec#appservice-https</a>22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseImplementation22222222-2222-2222-2222-2222222222221An adversary can gain access to sensitive data by sniffing traffic to Azure Web AppfalseI An adversary can fingerprint web application by leveraging server header information source is 'GE.EI' and target is 'SE.P.TMCore.WebApp' and target.80fe9520-5f00-4480-ad47-f2fd75dede82 is 'Azure' TH79UserThreatDescriptionfalse An adversary can fingerprint web application by leveraging server header information 22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseRemove standard server headers on Windows Azure Web Sites to avoid fingerprinting. Refer: <a href="https://aka.ms/tmtconfigmgmt#standard-finger">https://aka.ms/tmtconfigmgmt#standard-finger</a>22222222-2222-2222-2222-2222222222222PriorityfalseLow22222222-2222-2222-2222-2222222222221SDLPhasefalseImplementation22222222-2222-2222-2222-2222222222221An adversary can fingerprint an Azure web application by leveraging server header informationfalseIRobots.txt is often found in your site's root directory and exists to regulate the bots that crawl your site. This is where you can grant or deny permission to all or some specific search engine robots to access certain pages or your site as a whole. The standard for this file was developed in 1994 and is known as the Robots Exclusion Standard or Robots Exclusion Protocol. Detailed info about the robots.txt protocol can be found at robotstxt.org.(source is 'SE.EI.TMCore.Browser') and (target is 'SE.P.TMCore.WebApp')TH80UserThreatDescriptionfalseRobots.txt is often found in your site's root directory and exists to regulate the bots that crawl your site. This is where you can grant or deny permission to all or some specific search engine robots to access certain pages or your site as a whole. The standard for this file was developed in 1994 and is known as the Robots Exclusion Standard or Robots Exclusion Protocol. Detailed info about the robots.txt protocol can be found at robotstxt.org.22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseEnsure that administrative interfaces are appropriately locked down. Refer: <a href="https://aka.ms/tmtauthn#admin-interface-lockdown">https://aka.ms/tmtauthn#admin-interface-lockdown</a>22222222-2222-2222-2222-2222222222222PriorityfalseMedium22222222-2222-2222-2222-2222222222221SDLPhasefalseImplementation22222222-2222-2222-2222-2222222222221An adversary can gain access to certain pages or the site as a whole.falseISQL injection is an attack in which malicious code is inserted into strings that are later passed to an instance of SQL Server for parsing and execution. The primary form of SQL injection consists of direct insertion of code into user-input variables that are concatenated with SQL commands and executed. A less direct attack injects malicious code into strings that are destined for storage in a table or as metadata. When the stored strings are subsequently concatenated into a dynamic SQL command, the malicious code is executed. target is 'SE.DS.TMCore.SQL'TH82UserThreatDescriptionfalseSQL injection is an attack in which malicious code is inserted into strings that are later passed to an instance of SQL Server for parsing and execution. The primary form of SQL injection consists of direct insertion of code into user-input variables that are concatenated with SQL commands and executed. A less direct attack injects malicious code into strings that are destined for storage in a table or as metadata. When the stored strings are subsequently concatenated into a dynamic SQL command, the malicious code is executed. 22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseEnsure that login auditing is enabled on SQL Server. Refer: <a href="https://aka.ms/tmtauditlog#identify-sensitive-entities">https://aka.ms/tmtauditlog#identify-sensitive-entities</a> Ensure that least-privileged accounts are used to connect to Database server. Refer: <a href="https://aka.ms/tmtauthz#privileged-server">https://aka.ms/tmtauthz#privileged-server</a> Enable Threat detection on Azure SQL database. Refer: <a href="https://aka.ms/tmtauditlog#threat-detection">https://aka.ms/tmtauditlog#threat-detection</a> Do not use dynamic queries in stored procedures. Refer: <a href="https://aka.ms/tmtinputval#stored-proc">https://aka.ms/tmtinputval#stored-proc</a>22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseImplementation22222222-2222-2222-2222-2222222222221An adversary can gain access to sensitive data by performing SQL injectionfalseIAn adversary can gain access to the config files. and if sensitive data is stored in it, it would be compromised.target is 'SE.P.TMCore.WebAPI'TH83UserThreatDescriptionfalseAn adversary can gain access to the config files. and if sensitive data is stored in it, it would be compromised.22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseEncrypt sections of Web API's configuration files that contain sensitive data. Refer: <a href="https://aka.ms/tmtconfigmgmt#config-sensitive">https://aka.ms/tmtconfigmgmt#config-sensitive</a>22222222-2222-2222-2222-2222222222222PriorityfalseMedium22222222-2222-2222-2222-2222222222221SDLPhasefalseImplementation22222222-2222-2222-2222-2222222222221An adversary can gain access to sensitive data stored in Web API's config filesfalseIAn adversary may conduct man in the middle attack and downgrade TLS connection to clear text protocol, or forcing browser communication to pass through a proxy server that he controls. This may happen because the application may use mixed content or HTTP Strict Transport Security policy is not ensured.(source is 'SE.EI.TMCore.Browser' and target is 'SE.P.TMCore.WebApp')TH9UserThreatDescriptionfalseAn adversary may conduct man in the middle attack and downgrade TLS connection to clear text protocol, or forcing browser communication to pass through a proxy server that he controls. This may happen because the application may use mixed content or HTTP Strict Transport Security policy is not ensured.22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseApplications available over HTTPS must use secure cookies. Refer: <a href="https://aka.ms/tmtsmgmt#https-secure-cookies">https://aka.ms/tmtsmgmt#https-secure-cookies</a> Enable HTTP Strict Transport Security (HSTS). Refer: <a href="https://aka.ms/tmtcommsec#http-hsts">https://aka.ms/tmtcommsec#http-hsts</a>22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseImplementation22222222-2222-2222-2222-2222222222221An adversary can gain access to sensitive data by sniffing traffic to Web ApplicationfalseIIf an adversary can gain access to Azure VMs, sensitive data in the VM can be disclosed if the OS in the VM is not encryptedflow crosses 'SE.TB.TMCore.AzureIaaSVMTrustBoundary'TH93UserThreatDescriptionfalseIf an adversary can gain access to Azure VMs, sensitive data in the VM can be disclosed if the OS in the VM is not encrypted22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseUse Azure Disk Encryption to encrypt disks used by Virtual Machines. Refer: <a href="https://aka.ms/tmtdata#disk-vm">https://aka.ms/tmtdata#disk-vm</a>22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseDesign22222222-2222-2222-2222-2222222222221An adversary may gain access to sensitive data stored in Azure Virtual MachinesfalseIAn adversary can gain access to sensitive data such as the following, through verbose error messages - Server names - Connection strings - Usernames - Passwords - SQL procedures - Details of dynamic SQL failures - Stack trace and lines of code - Variables stored in memory - Drive and folder locations - Application install points - Host configuration settings - Other internal application details target is 'SE.P.TMCore.WebApp'TH94UserThreatDescriptionfalseAn adversary can gain access to sensitive data such as the following, through verbose error messages - Server names - Connection strings - Usernames - Passwords - SQL procedures - Details of dynamic SQL failures - Stack trace and lines of code - Variables stored in memory - Drive and folder locations - Application install points - Host configuration settings - Other internal application details 22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseDo not expose security details in error messages. Refer: <a href="https://aka.ms/tmtxmgmt#messages">https://aka.ms/tmtxmgmt#messages</a> Implement Default error handling page. Refer: <a href="https://aka.ms/tmtxmgmt#default">https://aka.ms/tmtxmgmt#default</a> Set Deployment Method to Retail in IIS. Refer: <a href="https://aka.ms/tmtxmgmt#deployment">https://aka.ms/tmtxmgmt#deployment</a> Exceptions should fail safely. Refer: <a href="https://aka.ms/tmtxmgmt#fail">https://aka.ms/tmtxmgmt#fail</a> ASP.NET applications must disable tracing and debugging prior to deployment. Refer: <a href="https://aka.ms/tmtconfigmgmt#trace-deploy">https://aka.ms/tmtconfigmgmt#trace-deploy</a> Implement controls to prevent username enumeration. Refer: <a href="https://aka.ms/tmtauthn#controls-username-enum">https://aka.ms/tmtauthn#controls-username-enum</a>22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseImplementation22222222-2222-2222-2222-2222222222221An adversary can gain access to sensitive information through error messagesfalseIAn adversary may gain access to sensitive data from uncleared browser cachesource is 'SE.EI.TMCore.Browser' and target is 'SE.P.TMCore.WebApp'TH99UserThreatDescriptionfalseAn adversary may gain access to sensitive data from uncleared browser cache22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseEnsure that sensitive content is not cached on the browser. Refer: <a href="https://aka.ms/tmtdata#cache-browser">https://aka.ms/tmtdata#cache-browser</a>22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseImplementation22222222-2222-2222-2222-2222222222221An adversary may gain access to sensitive data from uncleared browser cachefalseRAttacker can deny a malicious act on an API leading to repudiation issuestarget is 'SE.P.TMCore.WebAPI'TH109UserThreatDescriptionfalseAttacker can deny a malicious act on an API leading to repudiation issues22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseEnsure that auditing and logging is enforced on Web API. Refer: <a href="https://aka.ms/tmtauditlog#logging-web-api">https://aka.ms/tmtauditlog#logging-web-api</a>22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseDesign22222222-2222-2222-2222-2222222222221Attacker can deny a malicious act on an API leading to repudiation issuesfalseRThis is due to the Last Modified By field being overwritten on each save(target is 'SE.P.TMCore.DynamicsCRM')TH118UserThreatDescriptionfalseThis is due to the Last Modified By field being overwritten on each save22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseIdentify sensitive entities in your solution and implement change auditing. Refer: <a href="https://aka.ms/tmtauditlog#sensitive-entities">https://aka.ms/tmtauditlog#sensitive-entities</a>22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseDesign22222222-2222-2222-2222-2222222222221A malicious user can deny they made a change to {target.Name}falseRProper logging of all security events and user actions builds traceability in a system and denies any possible repudiation issues. In the absence of proper auditing and logging controls, it would become impossible to implement any accountability in a system.target is 'SE.DS.TMCore.AzureStorage'TH20UserThreatDescriptionfalseProper logging of all security events and user actions builds traceability in a system and denies any possible repudiation issues. In the absence of proper auditing and logging controls, it would become impossible to implement any accountability in a system.22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseUse Azure Storage Analytics to audit access of Azure Storage. If possible, audit the calls to the Azure Storage instance at the source of the call. Refer: <a href="https://aka.ms/tmt-th20">https://aka.ms/tmt-th20</a>22222222-2222-2222-2222-2222222222222PriorityfalseMedium22222222-2222-2222-2222-2222222222221SDLPhasefalseImplementation22222222-2222-2222-2222-2222222222221An adversary can deny actions on {target.Name} due to lack of auditing falseRProper logging of all security events and user actions builds traceability in a system and denies any possible repudiation issues. In the absence of proper auditing and logging controls, it would become impossible to implement any accountability in a system.target is 'SE.DS.TMCore.SQL' TH3UserThreatDescriptionfalseProper logging of all security events and user actions builds traceability in a system and denies any possible repudiation issues. In the absence of proper auditing and logging controls, it would become impossible to implement any accountability in a system.22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseEnsure that login auditing is enabled on SQL Server. Refer: <a href="https://aka.ms/tmtauditlog#identify-sensitive-entities">https://aka.ms/tmtauditlog#identify-sensitive-entities</a>22222222-2222-2222-2222-2222222222222PriorityfalseMedium22222222-2222-2222-2222-2222222222221SDLPhasefalseImplementation22222222-2222-2222-2222-2222222222221An adversary can deny actions on database due to lack of auditingfalseRProper logging of all security events and user actions builds traceability in a system and denies any possible repudiation issues. In the absence of proper auditing and logging controls, it would become impossible to implement any accountability in a systemtarget is 'SE.P.TMCore.WebApp'TH30UserThreatDescriptionfalseProper logging of all security events and user actions builds traceability in a system and denies any possible repudiation issues. In the absence of proper auditing and logging controls, it would become impossible to implement any accountability in a system22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseEnsure that auditing and logging is enforced on the application. Refer: <a href="https://aka.ms/tmtauditlog#auditing">https://aka.ms/tmtauditlog#auditing</a> Ensure that log rotation and separation are in place. Refer: <a href="https://aka.ms/tmtauditlog#log-rotation">https://aka.ms/tmtauditlog#log-rotation</a> Ensure that Audit and Log Files have Restricted Access. Refer: <a href="https://aka.ms/tmtauditlog#log-restricted-access">https://aka.ms/tmtauditlog#log-restricted-access</a> Ensure that User Management Events are Logged. Refer: <a href="https://aka.ms/tmtauditlog#user-management">https://aka.ms/tmtauditlog#user-management</a>22222222-2222-2222-2222-2222222222222PriorityfalseMedium22222222-2222-2222-2222-2222222222221SDLPhasefalseImplementation22222222-2222-2222-2222-2222222222221Attacker can deny the malicious act and remove the attack foot prints leading to repudiation issuesfalseRAn adversary may perform actions such as spoofing attempts, unauthorized access etc. on Cloud gateway. It is important to monitor these attempts so that adversary cannot deny these actionstarget is 'SE.GP.TMCore.IoTCloudGateway'TH34UserThreatDescriptionfalseAn adversary may perform actions such as spoofing attempts, unauthorized access etc. on Cloud gateway. It is important to monitor these attempts so that adversary cannot deny these actions22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseEnsure that appropriate auditing and logging is enforced on Cloud Gateway. Refer: <a href="https://aka.ms/tmtauditlog#logging-cloud-gateway">https://aka.ms/tmtauditlog#logging-cloud-gateway</a>22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseDesign22222222-2222-2222-2222-2222222222221An adversary can deny actions on Cloud Gateway due to lack of auditingfalseRAn adversary may perform actions such as spoofing attempts, unauthorized access etc. on Field gateway. It is important to monitor these attempts so that adversary cannot deny these actionstarget is 'SE.GP.TMCore.IoTFieldGateway'TH49UserThreatDescriptionfalseAn adversary may perform actions such as spoofing attempts, unauthorized access etc. on Field gateway. It is important to monitor these attempts so that adversary cannot deny these actions22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseEnsure that appropriate auditing and logging is enforced on Field Gateway. Refer: <a href="https://aka.ms/tmtauditlog#logging-field-gateway">https://aka.ms/tmtauditlog#logging-field-gateway</a>22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseDesign22222222-2222-2222-2222-2222222222221An adversary can deny actions on Field Gateway due to lack of auditingfalseRProper logging of all security events and user actions builds traceability in a system and denies any possible repudiation issues. In the absence of proper auditing and logging controls, it would become impossible to implement any accountability in a system. source is 'GE.EI' and target is 'SE.P.TMCore.WebApp' and target.80fe9520-5f00-4480-ad47-f2fd75dede82 is 'Azure'TH77UserThreatDescriptionfalseProper logging of all security events and user actions builds traceability in a system and denies any possible repudiation issues. In the absence of proper auditing and logging controls, it would become impossible to implement any accountability in a system. 22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseEnable diagnostics logging for web apps in Azure App Service. Refer: <a href="https://aka.ms/tmtauditlog#diagnostics-logging">https://aka.ms/tmtauditlog#diagnostics-logging</a>22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseImplementation22222222-2222-2222-2222-2222222222221An adversary can deny actions on Azure App Service due to lack of auditingfalseSAn adversary can bypass authentication due to non-standard Azure AD authentication schemestarget is 'SE.P.TMCore.AzureAD'TH11UserThreatDescriptionfalseAn adversary can bypass authentication due to non-standard Azure AD authentication schemes22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseUse standard authentication scenarios supported by Azure Active Directory. Refer: <a href="https://aka.ms/tmtauthn#authn-aad">https://aka.ms/tmtauthn#authn-aad</a>22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseImplementation22222222-2222-2222-2222-2222222222221An adversary can bypass authentication due to non-standard Azure AD authentication schemesfalseSAn adversary can bypass authentication due to non-standard Identity Server authentication schemestarget is 'SE.P.TMCore.IdSrv'TH111UserThreatDescriptionfalseAn adversary can bypass authentication due to non-standard Identity Server authentication schemes22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseUse standard authentication scenarios supported by Identity Server. Refer: <a href="https://aka.ms/tmtauthn#standard-authn-id">https://aka.ms/tmtauthn#standard-authn-id</a>22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseDesign22222222-2222-2222-2222-2222222222221An adversary can bypass authentication due to non-standard Identity Server authentication schemesfalseSAn adversary can get access to a user's session due to improper logout from Identity Servertarget is 'SE.P.TMCore.IdSrv'TH113UserThreatDescriptionfalseAn adversary can get access to a user's session due to improper logout from Identity Server22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseImplement proper logout when using Identity Server. Refer: <a href="https://aka.ms/tmtsmgmt#proper-logout">https://aka.ms/tmtsmgmt#proper-logout</a>22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseImplementation22222222-2222-2222-2222-2222222222221An adversary can get access to a user's session due to improper logout from Identity ServerfalseSAn adversary can abuse poorly managed signing keys of Identity Server. In case of key compromise, an adversary will be able to create valid auth tokens using the stolen keys and gain access to the resources protected by Identity server.target is 'SE.P.TMCore.IdSrv'TH114UserThreatDescriptionfalseAn adversary can abuse poorly managed signing keys of Identity Server. In case of key compromise, an adversary will be able to create valid auth tokens using the stolen keys and gain access to the resources protected by Identity server.22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseEnsure that signing keys are rolled over when using Identity Server. Refer: <a href="https://aka.ms/tmtcrypto#rolled-server">https://aka.ms/tmtcrypto#rolled-server</a>22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseDesign22222222-2222-2222-2222-2222222222221An adversary may issue valid tokens if Identity server's signing keys are compromisedfalseSAn adversary may spoof an Azure administrator and gain access to Azure subscription portal if the administrator's credentials are compromised.flow.23e2b6f4-fcd8-4e76-a04a-c9ff9aff4f59 is 'No'flow crosses 'SE.TB.TMCore.AzureTrustBoundary' TH117UserThreatDescriptionfalseAn adversary may spoof an Azure administrator and gain access to Azure subscription portal if the administrator's credentials are compromised.22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseEnable fine-grained access management to Azure Subscription using RBAC. Refer: <a href="https://aka.ms/tmtauthz#grained-rbac">https://aka.ms/tmtauthz#grained-rbac</a> Enable Azure Multi-Factor Authentication for Azure Administrators. Refer: <a href="https://aka.ms/tmtauthn#multi-factor-azure-admin">https://aka.ms/tmtauthn#multi-factor-azure-admin</a>22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseDesign22222222-2222-2222-2222-2222222222221An adversary may spoof an Azure administrator and gain access to Azure subscription portalfalseSAn adversary can get access to a user's session by replaying authentication tokens (source is 'GE.P' or source is 'GE.EI') and target is 'SE.P.TMCore.AzureAD'TH12UserThreatDescriptionfalseAn adversary can get access to a user's session by replaying authentication tokens 22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseEnsure that TokenReplayCache is used to prevent the replay of ADAL authentication tokens. Refer: <a href="https://aka.ms/tmtauthn#tokenreplaycache-adal">https://aka.ms/tmtauthn#tokenreplaycache-adal</a>22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseImplementation22222222-2222-2222-2222-2222222222221An adversary can get access to a user's session by replaying authentication tokens falseSAn adversary may gain access to the field gateway by leveraging default login credentials. target is 'SE.GP.TMCore.IoTFieldGateway'TH129UserThreatDescriptionfalseAn adversary may gain access to the field gateway by leveraging default login credentials. 22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseEnsure that the default login credentials of the field gateway are changed during installation. Refer: <a href="https://aka.ms/tmtconfigmgmt#default-change">https://aka.ms/tmtconfigmgmt#default-change</a>22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseDesign22222222-2222-2222-2222-2222222222221An adversary may gain access to the field gateway by leveraging default login credentials. falseSAn adversary can gain unauthorized access to API end points due to weak CORS configurationsource is 'SE.EI.TMCore.Browser' and target is 'SE.P.TMCore.WebAPI'TH13UserThreatDescriptionfalseAn adversary can gain unauthorized access to API end points due to weak CORS configuration22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseEnsure that only trusted origins are allowed if CORS is enabled on ASP.NET Web API. Refer: <a href="https://aka.ms/tmtconfigmgmt#cors-api">https://aka.ms/tmtconfigmgmt#cors-api</a> Mitigate against Cross-Site Request Forgery (CSRF) attacks on ASP.NET Web APIs. Refer: <a href="https://aka.ms/tmtsmgmt#csrf-api">https://aka.ms/tmtsmgmt#csrf-api</a>22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseImplementation22222222-2222-2222-2222-2222222222221An adversary can gain unauthorized access to API end points due to unrestricted cross domain requestsfalseSAn adversary may guess the client id and secrets of registered applications and impersonate them target is 'SE.P.TMCore.IdSrv'TH133UserThreatDescriptionfalseAn adversary may guess the client id and secrets of registered applications and impersonate them 22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseEnsure that cryptographically strong client id, client secret are used in Identity Server. Refer: <a href="https://aka.ms/tmtcrypto#client-server">https://aka.ms/tmtcrypto#client-server</a>22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseImplementation22222222-2222-2222-2222-2222222222221An adversary may guess the client id and secrets of registered applications and impersonate themfalseEAn adversary can gain unauthorized access to {target.Name} due to weak CORS configurationtarget is 'SE.DS.TMCore.AzureStorage' and target.c63455d0-ad77-4b08-aa02-9f8026bb056f is 'False'target is 'SE.DS.TMCore.AzureStorage'TH21UserThreatDescriptionfalseAn adversary can gain unauthorized access to {target.Name} due to weak CORS configuration22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseEnsure that only specific, trusted origins are allowed. Refer: <a href="https://aka.ms/tmt-th21">https://aka.ms/tmt-th21</a>22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseImplementation22222222-2222-2222-2222-2222222222221An adversary can gain unauthorized access to {target.Name} due to weak CORS configurationfalseSThe session cookies is the identifier by which the server knows the identity of current user for each incoming request. If the attacker is able to steal the user token he would be able to access all user data and perform all actions on behalf of user.source is 'SE.EI.TMCore.Browser' and target is 'SE.P.TMCore.WebApp'TH22UserThreatDescriptionfalseThe session cookies is the identifier by which the server knows the identity of current user for each incoming request. If the attacker is able to steal the user token he would be able to access all user data and perform all actions on behalf of user.22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseSet up session for inactivity lifetime. Refer: <a href="https://aka.ms/tmtsmgmt#inactivity-lifetime">https://aka.ms/tmtsmgmt#inactivity-lifetime</a> Implement proper logout from the application. Refer: <a href="https://aka.ms/tmtsmgmt#proper-app-logout">https://aka.ms/tmtsmgmt#proper-app-logout</a>22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseImplementation22222222-2222-2222-2222-2222222222221An adversary can get access to a user's session due to improper logout and timeoutfalseSThe session cookies is the identifier by which the server knows the identity of current user for each incoming request. If the attacker is able to steal the user token he would be able to access all user data and perform all actions on behalf of user.source is 'SE.EI.TMCore.Browser' and target is 'SE.P.TMCore.WebApp'TH23UserThreatDescriptionfalseThe session cookies is the identifier by which the server knows the identity of current user for each incoming request. If the attacker is able to steal the user token he would be able to access all user data and perform all actions on behalf of user.22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseEnable ValidateRequest attribute on ASP.NET Pages. Refer: <a href="https://aka.ms/tmtconfigmgmt#validate-aspnet">https://aka.ms/tmtconfigmgmt#validate-aspnet</a> Encode untrusted web output prior to rendering. Refer: <a href="https://aka.ms/tmtinputval#rendering">https://aka.ms/tmtinputval#rendering</a> Avoid using Html.Raw in Razor views. Refer: <a href="https://aka.ms/tmtinputval#html-razor">https://aka.ms/tmtinputval#html-razor</a> Sanitization should be applied on form fields that accept all characters e.g, rich text editor . Refer: <a href="https://aka.ms/tmtinputval#richtext">https://aka.ms/tmtinputval#richtext</a> Do not assign DOM elements to sinks that do not have inbuilt encoding . Refer: <a href="https://aka.ms/tmtinputval#inbuilt-encode">https://aka.ms/tmtinputval#inbuilt-encode</a>22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseImplementation22222222-2222-2222-2222-2222222222221An adversary can get access to a user's session due to insecure coding practicesfalseSEnsure that TLS certificate parameters are configured with correct valuestarget is 'SE.P.TMCore.WebApp'TH32UserThreatDescriptionfalseEnsure that TLS certificate parameters are configured with correct values22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseVerify X.509 certificates used to authenticate SSL, TLS, and DTLS connections. Refer: <a href="https://aka.ms/tmtcommsec#x509-ssltls">https://aka.ms/tmtcommsec#x509-ssltls</a>22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseImplementation22222222-2222-2222-2222-2222222222221An adversary can spoof the target web application due to insecure TLS certificate configurationfalseSAn adversary may replacing the {source.Name} or part of the {source.Name} with some other {source.Name}. (source is 'SE.EI.TMCore.IoTdevice' or source is 'SE.GP.TMCore.IoTFieldGateway') and (target is 'SE.GP.TMCore.IoTFieldGateway' or target is 'SE.GP.TMCore.IoTCloudGateway')TH35UserThreatDescriptionfalseAn adversary may replacing the {source.Name} or part of the {source.Name} with some other {source.Name}. 22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseEnsure that devices connecting to Field or Cloud gateway are authenticated. Refer: <a href="https://aka.ms/tmtauthn#authn-devices-cloud">https://aka.ms/tmtauthn#authn-devices-cloud</a>22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseDesign22222222-2222-2222-2222-2222222222221An adversary may spoof {source.Name} with a fake onefalseSAn attacker may extract cryptographic key material from {source.Name}, either at the software or hardware level, and subsequently access the system with a different physical or virtual {source.Name} under the identity of the {source.Name} the key material has been taken from. A good illustration is remote controls that can turn any TV and that are popular prankster tools.(source is 'SE.EI.TMCore.IoTdevice' or source is 'SE.GP.TMCore.IoTFieldGateway') and (target is 'SE.GP.TMCore.IoTFieldGateway' or target is 'SE.GP.TMCore.IoTCloudGateway')TH36UserThreatDescriptionfalseAn attacker may extract cryptographic key material from {source.Name}, either at the software or hardware level, and subsequently access the system with a different physical or virtual {source.Name} under the identity of the {source.Name} the key material has been taken from. A good illustration is remote controls that can turn any TV and that are popular prankster tools.22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseUse per-device authentication credentials. Refer: <a href="https://aka.ms/tmtauthn#authn-cred">https://aka.ms/tmtauthn#authn-cred</a>22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseDesign22222222-2222-2222-2222-2222222222221An adversary may reuse the authentication tokens of {source.Name} in anotherfalseSAn adversary may predict and generate valid security tokens to authenticate to IoT Hub, by leveraging weak encryption keys(source is 'SE.EI.TMCore.IoTdevice' or source is 'SE.GP.TMCore.IoTFieldGateway') and target is 'SE.GP.TMCore.IoTCloudGateway'TH40UserThreatDescriptionfalseAn adversary may predict and generate valid security tokens to authenticate to IoT Hub, by leveraging weak encryption keys22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseGenerate a random symmetric key of sufficient length for authentication to IoT Hub. Refer: <a href="https://aka.ms/tmtcrypto#random-hub">https://aka.ms/tmtcrypto#random-hub</a>22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseImplementation22222222-2222-2222-2222-2222222222221An adversary may auto-generate valid authentication tokens for IoT HubfalseSAn adversary may get access to SaS tokens used to authenticate to IoT Hub. If the lifetime of these tokens is not finite, the adversary may replay the stolen tokens indefinitely(source is 'SE.EI.TMCore.IoTdevice' or source is 'SE.GP.TMCore.IoTFieldGateway') and target is 'SE.GP.TMCore.IoTCloudGateway'TH44UserThreatDescriptionfalseAn adversary may get access to SaS tokens used to authenticate to IoT Hub. If the lifetime of these tokens is not finite, the adversary may replay the stolen tokens indefinitely22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseUse finite lifetimes for generated SaS tokens. Refer: <a href="https://aka.ms/tmtsmgmt#finite-tokens">https://aka.ms/tmtsmgmt#finite-tokens</a>22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseImplementation22222222-2222-2222-2222-2222222222221An adversary may replay stolen long-lived SaS tokens of IoT HubfalseSAn adversary may spoof a device and connect to field gateway. This may be achieved even when the device is registered in Cloud gateway since the field gateway may not be in sync with the device identities in cloud gatewaysource is 'SE.EI.TMCore.IoTdevice' and target is 'SE.GP.TMCore.IoTFieldGateway'TH50UserThreatDescriptionfalseAn adversary may spoof a device and connect to field gateway. This may be achieved even when the device is registered in Cloud gateway since the field gateway may not be in sync with the device identities in cloud gateway22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseAuthenticate devices connecting to the Field Gateway. Refer: <a href="https://aka.ms/tmtauthn#authn-devices-field">https://aka.ms/tmtauthn#authn-devices-field</a>22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseDesign22222222-2222-2222-2222-2222222222221An adversary may spoof a device and connect to field gatewayfalseEAn adversary may reuse a stolen long-lived resource token, access key or connection string to access an {target.Name} instancetarget is 'SE.P.TMCore.AzureDocumentDB'TH55UserThreatDescriptionfalseAn adversary may reuse a stolen long-lived resource token, access key or connection string to access an {target.Name} instance22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseUse minimum token lifetimes for generated resource tokens. Rotate secrets (e.g. resource tokens, access keys and passwords in connection strings) frequently, in accordance with your organization's policies. Refer: <a href="https://aka.ms/tmt-th55">https://aka.ms/tmt-th55</a>22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseImplementation22222222-2222-2222-2222-2222222222221An adversary may reuse a stolen long-lived resource token, access key or connection string to access an {target.Name} instancefalseSIf multiple devices use the same SaS token, then an adversary can spoof any device using a token that he or she has access totarget is 'SE.P.TMCore.AzureEventHub'TH58UserThreatDescriptionfalseIf multiple devices use the same SaS token, then an adversary can spoof any device using a token that he or she has access to22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseUse per device authentication credentials using SaS tokens. Refer: <a href="https://aka.ms/tmtauthn#authn-sas-tokens">https://aka.ms/tmtauthn#authn-sas-tokens</a>22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseImplementation22222222-2222-2222-2222-2222222222221An adversary may spoof a device by reusing the authentication tokens of one device in anotherfalseSIf a service fabric cluster is not secured, it allow any anonymous user to connect to it if it exposes management endpoints to the public Internet.flow.23e2b6f4-fcd8-4e76-a04a-c9ff9aff4f59 is 'No'flow crosses 'SE.TB.TMCore.ServiceFabric'TH68UserThreatDescriptionfalseIf a service fabric cluster is not secured, it allow any anonymous user to connect to it if it exposes management endpoints to the public Internet.22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseRestrict anonymous access to Service Fabric Cluster. Refer: <a href="https://aka.ms/tmtauthn#anon-access-cluster">https://aka.ms/tmtauthn#anon-access-cluster</a>22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseImplementation22222222-2222-2222-2222-2222222222221An adversary may gain unauthorized access to resources in Service FabricfalseSIf the same certificate that is used for node-to-node security is used for client-to-node security, it will be easy for an adversary to spoof and join a new node, in case the client-to-node certificate (which is often stored locally) is compromisedflow.23e2b6f4-fcd8-4e76-a04a-c9ff9aff4f59 is 'No'flow crosses 'SE.TB.TMCore.ServiceFabric'TH69UserThreatDescriptionfalseIf the same certificate that is used for node-to-node security is used for client-to-node security, it will be easy for an adversary to spoof and join a new node, in case the client-to-node certificate (which is often stored locally) is compromised22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseEnsure that Service Fabric client-to-node certificate is different from node-to-node certificate. Refer: <a href="https://aka.ms/tmtauthn#fabric-cn-nn">https://aka.ms/tmtauthn#fabric-cn-nn</a>22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseImplementation22222222-2222-2222-2222-2222222222221An adversary can spoof a node and access Service Fabric clusterfalseSAttackers can exploit weaknesses in system to steal user credentials. Downstream and upstream components are often accessed by using credentials stored in configuration stores. Attackers may steal the upstream or downstream component credentials. Attackers may steal credentials if, Credentials are stored and sent in clear text, Weak input validation coupled with dynamic sql queries, Password retrieval mechanism are poor, (target is 'SE.P.TMCore.WebApp')TH7UserThreatDescriptionfalseAttackers can exploit weaknesses in system to steal user credentials. Downstream and upstream components are often accessed by using credentials stored in configuration stores. Attackers may steal the upstream or downstream component credentials. Attackers may steal credentials if, Credentials are stored and sent in clear text, Weak input validation coupled with dynamic sql queries, Password retrieval mechanism are poor, 22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseExplicitly disable the autocomplete HTML attribute in sensitive forms and inputs. Refer: <a href="https://aka.ms/tmtdata#autocomplete-input">https://aka.ms/tmtdata#autocomplete-input</a> Perform input validation and filtering on all string type Model properties. Refer: <a href="https://aka.ms/tmtinputval#typemodel">https://aka.ms/tmtinputval#typemodel</a> Validate all redirects within the application are closed or done safely. Refer: <a href="https://aka.ms/tmtinputval#redirect-safe">https://aka.ms/tmtinputval#redirect-safe</a> Enable step up or adaptive authentication. Refer: <a href="https://aka.ms/tmtauthn#step-up-adaptive-authn">https://aka.ms/tmtauthn#step-up-adaptive-authn</a> Implement forgot password functionalities securely. Refer: <a href="https://aka.ms/tmtauthn#forgot-pword-fxn">https://aka.ms/tmtauthn#forgot-pword-fxn</a> Ensure that password and account policy are implemented. Refer: <a href="https://aka.ms/tmtauthn#pword-account-policy">https://aka.ms/tmtauthn#pword-account-policy</a> Implement input validation on all string type parameters accepted by Controller methods. Refer: <a href="https://aka.ms/tmtinputval#string-method">https://aka.ms/tmtinputval#string-method</a>22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseImplementation22222222-2222-2222-2222-2222222222221An adversary can steal sensitive data like user credentialsfalseSAzure AD authentication provides better control on identity management and hence it is a better alternative to authenticate clients to Service Fabricflow.23e2b6f4-fcd8-4e76-a04a-c9ff9aff4f59 is 'No'flow crosses 'SE.TB.TMCore.ServiceFabric'TH70UserThreatDescriptionfalseAzure AD authentication provides better control on identity management and hence it is a better alternative to authenticate clients to Service Fabric22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseUse AAD to authenticate clients to service fabric clusters. Refer: <a href="https://aka.ms/tmtauthn#aad-client-fabric">https://aka.ms/tmtauthn#aad-client-fabric</a>22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseDesign22222222-2222-2222-2222-2222222222221An adversary can potentially spoof a client if weaker client authentication channels are usedfalseSIf self-signed or test certificates are stolen, it would be difficult to revoke them. An adversary can use stolen certificates and continue to get access to Service Fabric cluster.flow.23e2b6f4-fcd8-4e76-a04a-c9ff9aff4f59 is 'No'flow crosses 'SE.TB.TMCore.ServiceFabric'TH72UserThreatDescriptionfalseIf self-signed or test certificates are stolen, it would be difficult to revoke them. An adversary can use stolen certificates and continue to get access to Service Fabric cluster.22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseEnsure that service fabric certificates are obtained from an approved Certificate Authority (CA). Refer: <a href="https://aka.ms/tmtauthn#fabric-cert-ca">https://aka.ms/tmtauthn#fabric-cert-ca</a>22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseDesign22222222-2222-2222-2222-2222222222221An adversary can spoof a node in Service Fabric cluster by using stolen certificatesfalseSOn a public client (e.g. a mobile device), refresh tokens may be stolen and used by an attacker to obtain access to the API. Depending on the client type, there are different ways that tokens may be revealed to an attacker and therefore different ways to protect them, some involving how the software using the tokens requests, stores and refreshes them.source is 'SE.EI.TMCore.Mobile' and target is 'SE.P.TMCore.WebAPI'TH74UserThreatDescriptionfalseOn a public client (e.g. a mobile device), refresh tokens may be stolen and used by an attacker to obtain access to the API. Depending on the client type, there are different ways that tokens may be revealed to an attacker and therefore different ways to protect them, some involving how the software using the tokens requests, stores and refreshes them.22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseUse ADAL libraries to manage token requests from OAuth2 clients to AAD (or on-premises AD). Refer: <a href="https://aka.ms/tmtauthn#adal-oauth2">https://aka.ms/tmtauthn#adal-oauth2</a>22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseImplementation22222222-2222-2222-2222-2222222222221An adversary obtains refresh or access tokens from {source.Name} and uses them to obtain access to the {target.Name} APIfalseSThe session cookies is the identifier by which the server knows the identity of current user for each incoming request. If the attacker is able to steal the user token he would be able to access all user data and perform all actions on behalf of user. source is 'SE.P.TMCore.WebApp' and target is 'SE.P.TMCore.AzureAD'TH75UserThreatDescriptionfalseThe session cookies is the identifier by which the server knows the identity of current user for each incoming request. If the attacker is able to steal the user token he would be able to access all user data and perform all actions on behalf of user. 22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseImplement proper logout using ADAL methods when using Azure AD. Refer: <a href="https://aka.ms/tmtsmgmt#logout-adal">https://aka.ms/tmtsmgmt#logout-adal</a>22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseImplementation22222222-2222-2222-2222-2222222222221An adversary can get access to a user's session due to improper logout from Azure ADfalseSThe session cookies is the identifier by which the server knows the identity of current user for each incoming request. If the attacker is able to steal the user token he would be able to access all user data and perform all actions on behalf of user. source is 'SE.P.TMCore.WebApp' and target is 'SE.P.TMCore.ADFS'TH76UserThreatDescriptionfalseThe session cookies is the identifier by which the server knows the identity of current user for each incoming request. If the attacker is able to steal the user token he would be able to access all user data and perform all actions on behalf of user. 22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseImplement proper logout using WsFederation methods when using ADFS. Refer: <a href="https://aka.ms/tmtsmgmt#wsfederation-logout">https://aka.ms/tmtsmgmt#wsfederation-logout</a>22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseImplementation22222222-2222-2222-2222-2222222222221An adversary can get access to a user's session due to improper logout from ADFSfalseSThe session cookies is the identifier by which the server knows the identity of current user for each incoming request. If the attacker is able to steal the user token he would be able to access all user data and perform all actions on behalf of user. (source is 'SE.EI.TMCore.Browser' and target is 'SE.P.TMCore.WebApp')TH8UserThreatDescriptionfalseThe session cookies is the identifier by which the server knows the identity of current user for each incoming request. If the attacker is able to steal the user token he would be able to access all user data and perform all actions on behalf of user. 22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseApplications available over HTTPS must use secure cookies. Refer: <a href="https://aka.ms/tmtsmgmt#https-secure-cookies">https://aka.ms/tmtsmgmt#https-secure-cookies</a> All http based application should specify http only for cookie definition. Refer: <a href="https://aka.ms/tmtsmgmt#cookie-definition">https://aka.ms/tmtsmgmt#cookie-definition</a>22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseImplementation22222222-2222-2222-2222-2222222222221Attackers can steal user session cookies due to insecure cookie attributesfalseSPhishing is attempted to obtain sensitive information such as usernames, passwords, and credit card details (and sometimes, indirectly, money), often for malicious reasons, by masquerading as a Web Server which is a trustworthy entity in electronic communicationtarget is 'SE.P.TMCore.WebApp'TH81UserThreatDescriptionfalsePhishing is attempted to obtain sensitive information such as usernames, passwords, and credit card details (and sometimes, indirectly, money), often for malicious reasons, by masquerading as a Web Server which is a trustworthy entity in electronic communication22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseVerify X.509 certificates used to authenticate SSL, TLS, and DTLS connections. Refer: <a href="https://aka.ms/tmtcommsec#x509-ssltls">https://aka.ms/tmtcommsec#x509-ssltls</a> Ensure that authenticated ASP.NET pages incorporate UI Redressing or clickjacking defences. Refer: <a href="https://aka.ms/tmtconfigmgmt#ui-defenses">https://aka.ms/tmtconfigmgmt#ui-defenses</a> Validate all redirects within the application are closed or done safely. Refer: <a href="https://aka.ms/tmtinputval#redirect-safe">https://aka.ms/tmtinputval#redirect-safe</a>22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseImplementation22222222-2222-2222-2222-2222222222221An adversary can create a fake website and launch phishing attacksfalseSAn adversary can gain access to Azure storage containers and blobs if anonymous access is provided to potentially sensitive data accidentally. target is 'SE.DS.TMCore.AzureStorage' and target.b3ece90f-c578-4a48-b4d4-89d97614e0d2 is 'Blob'TH85UserThreatDescriptionfalseAn adversary can gain access to Azure storage containers and blobs if anonymous access is provided to potentially sensitive data accidentally.22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseEnsure that only the required containers and blobs are given anonymous read access. Refer: <a href="https://aka.ms/tmt-th85">https://aka.ms/tmt-th85</a>22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseImplementation22222222-2222-2222-2222-2222222222221An adversary can access Azure storage blobs and containers anonymouslyfalseSIf proper authentication is not in place, an adversary can spoof a source process or external entity and gain unauthorized access to the Web Applicationtarget is 'SE.P.TMCore.WebApp'TH86UserThreatDescriptionfalseIf proper authentication is not in place, an adversary can spoof a source process or external entity and gain unauthorized access to the Web Application22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseConsider using a standard authentication mechanism to authenticate to Web Application. Refer: <a href="https://aka.ms/tmtauthn#standard-authn-web-app">https://aka.ms/tmtauthn#standard-authn-web-app</a>22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseDesign22222222-2222-2222-2222-2222222222221An adversary may spoof {source.Name} and gain access to Web ApplicationfalseSIf proper authentication is not in place, an adversary can spoof a source process or external entity and gain unauthorized access to the Web Application target is 'SE.P.TMCore.WebAPI'TH87UserThreatDescriptionfalseIf proper authentication is not in place, an adversary can spoof a source process or external entity and gain unauthorized access to the Web Application 22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseEnsure that standard authentication techniques are used to secure Web APIs. Refer: <a href="https://aka.ms/tmtauthn#authn-secure-api">https://aka.ms/tmtauthn#authn-secure-api</a>22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseDesign22222222-2222-2222-2222-2222222222221An adversary may spoof {source.Name} and gain access to Web APIfalseTAn adversary can execute remote code on the server through XSLT scriptingtarget is 'SE.P.TMCore.WebApp' and target.df53c172-b70c-412c-9e99-a6fbc10748ee is 'Yes'TH100UserThreatDescriptionfalseAn adversary can execute remote code on the server through XSLT scripting22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseDisable XSLT scripting for all transforms using untrusted style sheets. Refer: <a href="https://aka.ms/tmtinputval#disable-xslt">https://aka.ms/tmtinputval#disable-xslt</a>22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseImplementation22222222-2222-2222-2222-2222222222221An adversary can execute remote code on the server through XSLT scriptingfalseTAn adversary can tamper critical database securables and deny the actiontarget is 'SE.DS.TMCore.SQL'TH105UserThreatDescriptionfalseAn adversary can tamper critical database securables and deny the action22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseAdd digital signature to critical database securables. Refer: <a href="https://aka.ms/tmtcrypto#securables-db">https://aka.ms/tmtcrypto#securables-db</a>22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseDesign22222222-2222-2222-2222-2222222222221An adversary can tamper critical database securables and deny the actionfalseTAn adversary may inject malicious inputs into an API and affect downstream processestarget is 'SE.P.TMCore.WebAPI'TH108UserThreatDescriptionfalseAn adversary may inject malicious inputs into an API and affect downstream processes22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseEnsure that model validation is done on Web API methods. Refer: <a href="https://aka.ms/tmtinputval#validation-api">https://aka.ms/tmtinputval#validation-api</a> Implement input validation on all string type parameters accepted by Web API methods. Refer: <a href="https://aka.ms/tmtinputval#string-api">https://aka.ms/tmtinputval#string-api</a>22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseImplementation22222222-2222-2222-2222-2222222222221An adversary may inject malicious inputs into an API and affect downstream processesfalseTAn Adversary can view the message and may tamper the message target is 'SE.P.TMCore.WCF'TH132UserThreatDescriptionfalseAn Adversary can view the message and may tamper the message 22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseWCF: Set Message security Protection level to EncryptAndSign. Refer: <a href="https://aka.ms/tmtcommsec#message-protection">https://aka.ms/tmtcommsec#message-protection</a>22222222-2222-2222-2222-2222222222222PriorityfalseMedium22222222-2222-2222-2222-2222222222221SDLPhasefalseImplementation22222222-2222-2222-2222-2222222222221An Adversary can view the message and may tamper the message falseTAn adversary may spread malware, steal or tamper data due to lack of endpoint protection on devices. Scenarios such as stealing a user's laptop and extracting data from hard disk, luring users to install malware, exploit unpatched OS etc. flow.23e2b6f4-fcd8-4e76-a04a-c9ff9aff4f59 is 'No' flow crosses 'SE.TB.TMCore.MachineTrustBoundary'TH134UserThreatDescriptionfalseAn adversary may spread malware, steal or tamper data due to lack of endpoint protection on devices. Scenarios such as stealing a user's laptop and extracting data from hard disk, luring users to install malware, exploit unpatched OS etc. 22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseEnsure that devices have end point security controls configured as per organizational policies. Refer: <a href="https://aka.ms/tmtconfigmgmt#controls-policies">https://aka.ms/tmtconfigmgmt#controls-policies</a>22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseDesign22222222-2222-2222-2222-2222222222221An adversary may spread malware, steal or tamper data due to lack of endpoint protection on devicesfalseTAn adversary may reverse engineer deployed binariesflow.23e2b6f4-fcd8-4e76-a04a-c9ff9aff4f59 is 'No'flow crosses 'SE.TB.TMCore.MachineTrustBoundary'TH137UserThreatDescriptionfalseAn adversary may reverse engineer deployed binaries22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseEnsure that binaries are obfuscated if they contain sensitive information. Refer: <a href="https://aka.ms/tmtdata#binaries-info">https://aka.ms/tmtdata#binaries-info</a>22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseImplementation22222222-2222-2222-2222-2222222222221An adversary may reverse engineer deployed binariesfalseTAn adversary may tamper deployed binariesflow.23e2b6f4-fcd8-4e76-a04a-c9ff9aff4f59 is 'No'flow crosses 'SE.TB.TMCore.MachineTrustBoundary'TH138UserThreatDescriptionfalseAn adversary may tamper deployed binaries22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseEnsure that deployed application's binaries are digitally signed. Refer: <a href="https://aka.ms/tmtauthn#binaries-signed">https://aka.ms/tmtauthn#binaries-signed</a>22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseDesign22222222-2222-2222-2222-2222222222221An adversary may tamper deployed binariesfalseTWebsite defacement is an attack on a website where the attacker changes the visual appearance of the site or a webpage. source is 'SE.EI.TMCore.Browser' and target is 'SE.P.TMCore.WebApp'TH24UserThreatDescriptionfalseWebsite defacement is an attack on a website where the attacker changes the visual appearance of the site or a webpage. 22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseImplement Content Security Policy (CSP), and disable inline javascript. Refer: <a href="https://aka.ms/tmtconfigmgmt#csp-js">https://aka.ms/tmtconfigmgmt#csp-js</a> Enable browser's XSS filter. Refer: <a href="https://aka.ms/tmtconfigmgmt#xss-filter">https://aka.ms/tmtconfigmgmt#xss-filter</a> Access third party javascripts from trusted sources only. Refer: <a href="https://aka.ms/tmtconfigmgmt#js-trusted">https://aka.ms/tmtconfigmgmt#js-trusted</a> Enable ValidateRequest attribute on ASP.NET Pages. Refer: <a href="https://aka.ms/tmtconfigmgmt#validate-aspnet">https://aka.ms/tmtconfigmgmt#validate-aspnet</a> Ensure that each page that could contain user controllable content opts out of automatic MIME sniffing . Refer: <a href="https://aka.ms/tmtinputval#out-sniffing">https://aka.ms/tmtinputval#out-sniffing</a> Use locally-hosted latest versions of JavaScript libraries . Refer: <a href="https://aka.ms/tmtconfigmgmt#local-js">https://aka.ms/tmtconfigmgmt#local-js</a> Ensure appropriate controls are in place when accepting files from users. Refer: <a href="https://aka.ms/tmtinputval#controls-users">https://aka.ms/tmtinputval#controls-users</a> Disable automatic MIME sniffing. Refer: <a href="https://aka.ms/tmtconfigmgmt#mime-sniff">https://aka.ms/tmtconfigmgmt#mime-sniff</a> Encode untrusted web output prior to rendering. Refer: <a href="https://aka.ms/tmtinputval#rendering">https://aka.ms/tmtinputval#rendering</a> Perform input validation and filtering on all string type Model properties. Refer: <a href="https://aka.ms/tmtinputval#typemodel">https://aka.ms/tmtinputval#typemodel</a> Ensure that the system has inbuilt defences against misuse. Refer: <a href="https://aka.ms/tmtauditlog#inbuilt-defenses">https://aka.ms/tmtauditlog#inbuilt-defenses</a> Enable HTTP Strict Transport Security (HSTS). Refer: <a href="https://aka.ms/tmtcommsec#http-hsts">https://aka.ms/tmtcommsec#http-hsts</a> Implement input validation on all string type parameters accepted by Controller methods. Refer: <a href="https://aka.ms/tmtinputval#string-method">https://aka.ms/tmtinputval#string-method</a> Avoid using Html.Raw in Razor views. Refer: <a href="https://aka.ms/tmtinputval#html-razor">https://aka.ms/tmtinputval#html-razor</a> Sanitization should be applied on form fields that accept all characters e.g, rich text editor . Refer: <a href="https://aka.ms/tmtinputval#richtext">https://aka.ms/tmtinputval#richtext</a> Do not assign DOM elements to sinks that do not have inbuilt encoding . Refer: <a href="https://aka.ms/tmtinputval#inbuilt-encode">https://aka.ms/tmtinputval#inbuilt-encode</a>22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseImplementation22222222-2222-2222-2222-2222222222221An adversary can deface the target web application by injecting malicious code or uploading dangerous filesfalseTAn attacker steals messages off the network and replays them in order to steal a user's session(source is 'SE.EI.TMCore.Browser' and target is 'SE.P.TMCore.WebApp')TH33UserThreatDescriptionfalseAn attacker steals messages off the network and replays them in order to steal a user's session22222222-2222-2222-2222-2222222222220PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseImplementation22222222-2222-2222-2222-2222222222221An attacker steals messages off the network and replays them in order to steal a user's sessionfalseTAn adversary may leverage known vulnerabilities and exploit a device if the firmware of the device is not updatedsource is 'SE.EI.TMCore.IoTdevice' or source is 'SE.GP.TMCore.IoTFieldGateway'TH39UserThreatDescriptionfalseAn adversary may leverage known vulnerabilities and exploit a device if the firmware of the device is not updated22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseEnsure that the Cloud Gateway implements a process to keep the connected devices firmware up to date. Refer: <a href="https://aka.ms/tmtconfigmgmt#cloud-firmware">https://aka.ms/tmtconfigmgmt#cloud-firmware</a>22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseDesign22222222-2222-2222-2222-2222222222221An adversary may exploit known vulnerabilities in unpatched devicesfalseTAn adversary may partially or wholly replace the software running on {target.Name}, potentially allowing the replaced software to leverage the genuine identity of the device if the key material or the cryptographic facilities holding key materials were available to the illicit program. For example an attacker may leverage extracted key material to intercept and suppress data from the device on the communication path and replace it with false data that is authenticated with the stolen key material.source is 'SE.EI.TMCore.IoTdevice' or source is 'SE.GP.TMCore.IoTFieldGateway'TH43UserThreatDescriptionfalseAn adversary may partially or wholly replace the software running on {target.Name}, potentially allowing the replaced software to leverage the genuine identity of the device if the key material or the cryptographic facilities holding key materials were available to the illicit program. For example an attacker may leverage extracted key material to intercept and suppress data from the device on the communication path and replace it with false data that is authenticated with the stolen key material.22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseStore Cryptographic Keys securely on IoT Device. Refer: <a href="https://aka.ms/tmtcrypto#keys-iot">https://aka.ms/tmtcrypto#keys-iot</a>22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseDesign22222222-2222-2222-2222-2222222222221An adversary may tamper {source.Name} and extract cryptographic key material from itfalseTAn adversary may perform a Man-In-The-Middle attack on the encrypted traffic sent to {target.Name}(source is 'SE.GP.TMCore.IoTFieldGateway' or source is 'SE.GP.TMCore.IoTCloudGateway') and (target is 'SE.EI.TMCore.IoTdevice' or target is 'SE.GP.TMCore.IoTFieldGateway')TH45UserThreatDescriptionfalseAn adversary may perform a Man-In-The-Middle attack on the encrypted traffic sent to {target.Name}22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseVerify X.509 certificates used to authenticate SSL, TLS, and DTLS connections. Refer: <a href="https://aka.ms/tmtcommsec#x509-ssltls">https://aka.ms/tmtcommsec#x509-ssltls</a>22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseImplementation22222222-2222-2222-2222-2222222222221An adversary may attempt to intercept encrypted traffic sent to {target.Name}falseTAn adversary may launch malicious code into {target.Name} and execute ittarget is 'SE.EI.TMCore.IoTdevice' or target is 'SE.GP.TMCore.IoTFieldGateway'TH46UserThreatDescriptionfalseAn adversary may launch malicious code into {target.Name} and execute it22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseEnsure that unknown code cannot execute on devices. Refer: <a href="https://aka.ms/tmtconfigmgmt#unknown-exe">https://aka.ms/tmtconfigmgmt#unknown-exe</a>22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseDesign22222222-2222-2222-2222-2222222222221An adversary may execute unknown code on {target.Name}falseTAn adversary may launch offline attacks made by disabling or circumventing the installed operating system, or made by physically separating the storage media from the device in order to attack the data separately.source is 'SE.EI.TMCore.IoTdevice'TH47UserThreatDescriptionfalseAn adversary may launch offline attacks made by disabling or circumventing the installed operating system, or made by physically separating the storage media from the device in order to attack the data separately.22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseEncrypt OS and additional partitions of IoT Device with Bitlocker. Refer: <a href="https://aka.ms/tmtconfigmgmt#partition-iot">https://aka.ms/tmtconfigmgmt#partition-iot</a>22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseDesign22222222-2222-2222-2222-2222222222221An adversary may tamper the OS of a device and launch offline attacksfalseTAn adversary may eavesdrop and interfere with the communication between a client and Event Hub and possibly tamper the data that is transmittedtarget is 'SE.P.TMCore.AzureEventHub'TH61UserThreatDescriptionfalseAn adversary may eavesdrop and interfere with the communication between a client and Event Hub and possibly tamper the data that is transmitted22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseSecure communication to Event Hub using SSL/TLS. Refer: <a href="https://aka.ms/tmtcommsec#comm-ssltls">https://aka.ms/tmtcommsec#comm-ssltls</a>22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseDesign22222222-2222-2222-2222-2222222222221An adversary may eavesdrop the communication between the a client and Event HubfalseTAn adversary can tamper the data uploaded to {target.Name} storage when HTTPS cannot be enabled.target is 'SE.DS.TMCore.AzureStorage' and target.b3ece90f-c578-4a48-b4d4-89d97614e0d2 is 'Blob' and target.229f2e53-bc3f-476c-8ac9-57da37efd00f is 'True'target is 'SE.DS.TMCore.AzureStorage' and target.b3ece90f-c578-4a48-b4d4-89d97614e0d2 is 'Blob'TH66UserThreatDescriptionfalseAn adversary can tamper the data uploaded to {target.Name} storage when HTTPS cannot be enabled.22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseValidate the hash (which should be generated using a cryptographically strong hashing algorithm) after downloading the blob if HTTPS cannot be enabled.22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseImplementation22222222-2222-2222-2222-2222222222221An adversary can tamper the data uploaded to {target.Name} when HTTPS cannot be enabledfalseTThe source of a package is the individual or organization that created the package. Running a package from an unknown or untrusted source might be risky.target is 'SE.DS.TMCore.SQL' and target.649208cc-3b55-40ff-94b9-015c0fb0c9e8 is 'Yes'TH88UserThreatDescriptionfalseThe source of a package is the individual or organization that created the package. Running a package from an unknown or untrusted source might be risky.22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseSSIS packages should be encrypted and digitally signed . Refer: <a href="https://aka.ms/tmtcrypto#ssis-signed">https://aka.ms/tmtcrypto#ssis-signed</a>22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseDesign22222222-2222-2222-2222-2222222222221An adversary can tamper SSIS packages and cause undesirable consequencesfalseTAn adversary may leverage the lack of intrusion detection and prevention of anomalous database activities and trigger anomalous traffic to databasetarget is 'SE.DS.TMCore.SQL'TH89UserThreatDescriptionfalseAn adversary may leverage the lack of intrusion detection and prevention of anomalous database activities and trigger anomalous traffic to database22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseEnable Threat detection on Azure SQL database. Refer: <a href="https://aka.ms/tmtauditlog#threat-detection">https://aka.ms/tmtauditlog#threat-detection</a>22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseDesign22222222-2222-2222-2222-2222222222221An adversary may leverage the lack of monitoring systems and trigger anomalous traffic to databasefalseTAn adversary may gain unauthorized access to {source.Name}, tamper its OS and get access to confidential information in the field gatewaysource is 'SE.GP.TMCore.IoTFieldGateway'TH92UserThreatDescriptionfalseAn adversary may gain unauthorized access to {source.Name}, tamper its OS and get access to confidential information in the field gateway22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseEncrypt OS and additional partitions of IoT Field Gateway with Bitlocker. Refer: <a href="https://aka.ms/tmtconfigmgmt#field-bitlocker">https://aka.ms/tmtconfigmgmt#field-bitlocker</a>22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseDesign22222222-2222-2222-2222-2222222222221An adversary may gain unauthorized access to IoT Field Gateway and tamper its OSfalseTAn adversary can use various tools, reverse engineer binaries and abuse them by tamperingsource is 'SE.EI.TMCore.Mobile'TH95UserThreatDescriptionfalseAn adversary can use various tools, reverse engineer binaries and abuse them by tampering22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseObfuscate generated binaries before distributing to end users. Refer: <a href="https://aka.ms/tmtdata#binaries-end">https://aka.ms/tmtdata#binaries-end</a>22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseDesign22222222-2222-2222-2222-2222222222221An adversary can reverse engineer and tamper binariesfalseTSQL injection is an attack in which malicious code is inserted into strings that are later passed to an instance of SQL Server for parsing and execution. The primary form of SQL injection consists of direct insertion of code into user-input variables that are concatenated with SQL commands and executed. A less direct attack injects malicious code into strings that are destined for storage in a table or as metadata. When the stored strings are subsequently concatenated into a dynamic SQL command, the malicious code is executed. target is 'SE.P.TMCore.WebApp'TH96UserThreatDescriptionfalseSQL injection is an attack in which malicious code is inserted into strings that are later passed to an instance of SQL Server for parsing and execution. The primary form of SQL injection consists of direct insertion of code into user-input variables that are concatenated with SQL commands and executed. A less direct attack injects malicious code into strings that are destined for storage in a table or as metadata. When the stored strings are subsequently concatenated into a dynamic SQL command, the malicious code is executed. 22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseEnsure that type-safe parameters are used in Web Application for data access. Refer: <a href="https://aka.ms/tmtinputval#typesafe">https://aka.ms/tmtinputval#typesafe</a>22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseImplementation22222222-2222-2222-2222-2222222222221An adversary can gain access to sensitive data by performing SQL injection through Web AppfalseTSQL injection is an attack in which malicious code is inserted into strings that are later passed to an instance of SQL Server for parsing and execution. The primary form of SQL injection consists of direct insertion of code into user-input variables that are concatenated with SQL commands and executed. A less direct attack injects malicious code into strings that are destined for storage in a table or as metadata. When the stored strings are subsequently concatenated into a dynamic SQL command, the malicious code is executed. target is 'SE.P.TMCore.WebAPI'TH97UserThreatDescriptionfalseSQL injection is an attack in which malicious code is inserted into strings that are later passed to an instance of SQL Server for parsing and execution. The primary form of SQL injection consists of direct insertion of code into user-input variables that are concatenated with SQL commands and executed. A less direct attack injects malicious code into strings that are destined for storage in a table or as metadata. When the stored strings are subsequently concatenated into a dynamic SQL command, the malicious code is executed. 22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseEnsure that type-safe parameters are used in Web API for data access. Refer: <a href="https://aka.ms/tmtinputval#typesafe-api">https://aka.ms/tmtinputval#typesafe-api</a>22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseImplementation22222222-2222-2222-2222-2222222222221An adversary can gain access to sensitive data by performing SQL injection through Web APIfalseTAn adversary can gain access to the config files. and if sensitive data is stored in it, it would be compromised.target is 'SE.P.TMCore.WebApp'TH98UserThreatDescriptionfalseAn adversary can gain access to the config files. and if sensitive data is stored in it, it would be compromised.22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseEncrypt sections of Web App's configuration files that contain sensitive data. Refer: <a href="https://aka.ms/tmtdata#encrypt-data">https://aka.ms/tmtdata#encrypt-data</a>22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseImplementation22222222-2222-2222-2222-2222222222221An adversary can gain access to sensitive data stored in Web App's config filesfalseEAn adversary can gain unauthorized access to Azure SQL DB instances due to weak network security configuration.target is 'SE.DS.TMCore.AzureSQLDB' and not target.e68e212d-896e-403e-8a2d-8c6d2b2505df is 'Allow access from selected networks'TH143UserThreatDescriptionfalseAn adversary can gain unauthorized access to Azure SQL DB instances due to weak network security configuration.22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseRestrict access to Azure SQL Database instances by configuring server-level and database-level firewall rules to permit connections from selected networks (e.g. a virtual network or a custom set of IP addresses) where possible. Refer:<a href="https://aka.ms/tmt-th143">https://aka.ms/tmt-th143</a>22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseImplementation22222222-2222-2222-2222-2222222222221An adversary can gain unauthorized access to Azure SQL DB instances due to weak network security configuration.falseIAn adversary can read confidential data due to weak connection string configuration.target is 'SE.DS.TMCore.AzureSQLDB'TH144UserThreatDescriptionfalseAn adversary can read confidential data due to weak connection string configuration.22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseClients connecting to an Azure SQL Database instance using a connection string should ensure encrypt=true and trustservercertificate=false are set. This configuration ensures that connections are encrypted only if there is a verifiable server certificate (otherwise the connection attempt fails). This helps protect against Man-In-The-Middle attacks. Refer: <a href="https://aka.ms/tmt-th144">https://aka.ms/tmt-th144</a>22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseImplementation22222222-2222-2222-2222-2222222222221An adversary can read confidential data due to weak connection string configurationfalseIAn adversary having access to the storage container (e.g. physical access to the storage media) may be able to read sensitive data.target is 'SE.DS.TMCore.AzureSQLDB' and not target.3a2a095f-94bc-467f-987c-8dac8307cdc6 is 'True'TH145UserThreatDescriptionfalseAn adversary having access to the storage container (e.g. physical access to the storage media) may be able to read sensitive data.22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseEnable Transparent Data Encryption (TDE) on Azure SQL Database instances to have data encrypted at rest. Refer:<a href="https://aka.ms/tmt-th145a">https://aka.ms/tmt-th145a</a>. Use the Always Encrypted feature to allow client applications to encrypt sensitive data before it is sent to the Azure SQL Database. Refer: <a href="https://aka.ms/tmt-th145b">https://aka.ms/tmt-th145b</a> 22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseImplementation22222222-2222-2222-2222-2222222222221An adversary having access to the storage container (e.g. physical access to the storage media) may be able to read sensitive datafalseEA compromised identity may permit more privileges than intended to an adversary due to weak permission and role assignments.target is 'SE.DS.TMCore.AzureSQLDB'TH146UserThreatDescriptionfalseA compromised identity may permit more privileges than intended to an adversary due to weak permission and role assignments.22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseIt is recommended to review permission and role assignments to ensure the users are granted the least privileges necessary. Refer: <a href="https://aka.ms/tmt-th146">https://aka.ms/tmt-th146</a>22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseImplementation22222222-2222-2222-2222-2222222222221A compromised identity may permit more privileges than intended to an adversary due to weak permission and role assignmentsfalseRAn adversary can deny actions performed on {target.Name} due to a lack of auditing.target is 'SE.DS.TMCore.AzureSQLDB' and target.6a3509e5-a3fd-41db-8dea-6fb44b031e4b is 'True'target is 'SE.DS.TMCore.AzureSQLDB'TH147UserThreatDescriptionfalseAn adversary can deny actions performed on {target.Name} due to a lack of auditing.22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseEnable auditing on Azure SQL Database instances to track and log database events. After configuring and customizing the audited events, enable threat detection to receive alerts on anomalous database activities indicating potential security threats. Refer: <a href="https://aka.ms/tmt-th147">https://aka.ms/tmt-th147</a>22222222-2222-2222-2222-2222222222222PriorityfalseMedium22222222-2222-2222-2222-2222222222221SDLPhasefalseDesign22222222-2222-2222-2222-2222222222221An adversary can deny actions performed on {target.Name} due to a lack of auditingfalseEAn adversary can gain long term, persistent access to an Azure SQL DB instance through the compromise of local user account password(s).target is 'SE.DS.TMCore.AzureSQLDB'TH148UserThreatDescriptionfalseAn adversary can gain long term, persistent access to an Azure SQL DB instance through the compromise of local user account password(s).22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseIt is recommended to rotate user account passwords (e.g. those used in connection strings) regularly, in accordance with your organization's policies. Store secrets in a secret storage solution (e.g. Azure Key Vault).22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseImplementation22222222-2222-2222-2222-2222222222221An adversary can gain long term, persistent access to an Azure SQL DB instance through the compromise of local user account password(s)falseEAn adversary may abuse weak {target.Name} configuration.target is 'SE.DS.TMCore.AzureSQLDB' and target.212cf67e-047a-4617-860f-92282e04b8d8 is 'True'target is 'SE.DS.TMCore.AzureSQLDB'TH149UserThreatDescriptionfalseAn adversary may abuse weak {target.Name} configuration.22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseEnable SQL Vulnerability Assessment to gain visibility into the security posture of your Azure SQL Database instances. Acting on the assessment results help reduce attack surface and enhance your database security. Refer: <a href="https://aka.ms/tmt-th149">https://aka.ms/tmt-th149</a>22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseImplementation22222222-2222-2222-2222-2222222222221An adversary may abuse weak {target.Name} configurationfalseEAn adversary can gain unauthorized access to {target.Name} instances due to weak network security configuration.target is 'SE.DS.TMCore.AzureMySQLDB' and not target.9afccb81-bc8b-4527-ad05-f90ec3e396cb is 'Allow access from selected networks'TH150UserThreatDescriptionfalseAn adversary can gain unauthorized access to Azure MySQL DB instances due to weak network security configuration.22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseRestrict access to Azure MySQL DB instances by configuring server-level firewall rules to only permit connections from selected IP addresses where possible. Refer: <a href="https://aka.ms/tmt-th150">https://aka.ms/tmt-th150</a>22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseImplementation22222222-2222-2222-2222-2222222222221An adversary can gain unauthorized access to Azure MySQL DB instances due to weak network security configurationfalseTAn adversary may read and/or tamper with the data transmitted to {target.Name} due to weak configuration.target is 'SE.DS.TMCore.AzureMySQLDB' and not target.4d3b2548-8c31-460e-88e5-4c26135003ac is 'True'TH151UserThreatDescriptionfalseAn adversary may read and/or tamper with the data transmitted to Azure MySQL DB due to weak configuration.22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseEnforce communication between clients and Azure MySQL DB to be over SSL/TLS by enabling the Enforce SSL connection feature on the server. Check that the connection strings used to connect to MySQL databases have the right configuration (e.g. ssl = true or sslmode=require or sslmode=true are set). Refer: <a href="https://aka.ms/tmt-th151a">https://aka.ms/tmt-th151a</a> Configure MySQL server to use a verifiable SSL certificate (needed for SSL/TLS communication). Refer: <a href="https://aka.ms/tmt-th151b">https://aka.ms/tmt-th151b</a>22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseImplementation22222222-2222-2222-2222-2222222222221An adversary may read and/or tamper with the data transmitted to Azure MySQL DB due to weak configurationfalseEAn adversary can gain long term, persistent access to {target.Name} instance through the compromise of local user account password(s).target is 'SE.DS.TMCore.AzureMySQLDB'TH152UserThreatDescriptionfalseAn adversary can gain long term, persistent access to an Azure MySQL DB instance through the compromise of local user account password(s).22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseIt is recommended to rotate user account passwords (e.g. those used in connection strings) regularly, in accordance with your organization's policies. Store secrets in a secret storage solution (e.g. Azure Key Vault).22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseImplementation22222222-2222-2222-2222-2222222222221An adversary can gain long term, persistent access to an Azure MySQL DB instance through the compromise of local user account password(s)falseEAn adversary can gain unauthorized access to {target.Name} instances due to weak network security configuration.target is 'SE.DS.TMCore.AzurePostgresDB' and not target.ba682010-cfcf-4916-9f88-524f8d9ce8a8 is 'Allow access from selected networks'TH153UserThreatDescriptionfalseAn adversary can gain unauthorized access to Azure Postgres DB instances due to weak network security configuration.22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseRestrict access to Azure Postgres DB instances by configuring server-level firewall rules to only permit connections from selected IP addresses where possible. Refer: <a href="https://aka.ms/tmt-th153">https://aka.ms/tmt-th153</a>22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseImplementation22222222-2222-2222-2222-2222222222221An adversary can gain unauthorized access to Azure Postgres DB instances due to weak network security configurationfalseTAn adversary may read and/or tamper with the data transmitted to {target.Name} due to weak configuration.target is 'SE.DS.TMCore.AzurePostgresDB' and not target.65a8827c-6efd-4243-aa81-0625c4aea98e is 'True'TH154UserThreatDescriptionfalseAn adversary may read and/or tamper with the data transmitted to Azure Postgres DB due to weak configuration.22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseEnforce communication between clients and Azure Postgres DB to be over SSL/TLS by enabling the Enforce SSL connection feature on the server. Check that the connection strings used to connect to MySQL databases have the right configuration (e.g. ssl = true or sslmode=require or sslmode=true are set). Refer: <a href="https://aka.ms/tmt-th154a">https://aka.ms/tmt-th154a</a> Configure MySQL server to use a verifiable SSL certificate (needed for SSL/TLS communication). Refer: <a href="https://aka.ms/tmt-th154b">https://aka.ms/tmt-th154b</a>22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseImplementation22222222-2222-2222-2222-2222222222221An adversary may read and/or tamper with the data transmitted to Azure Postgres DB due to weak configurationfalseEAn adversary can gain long term, persistent access to {target.Name} instance through the compromise of local user account password(s).target is 'SE.DS.TMCore.AzurePostgresDB'TH155UserThreatDescriptionfalseAn adversary can gain long term, persistent access to an Azure Postgres DB instance through the compromise of local user account password(s).22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseIt is recommended to rotate user account passwords (e.g. those used in connection strings) regularly, in accordance with your organization's policies. Store secrets in a secret storage solution (e.g. Azure Key Vault).22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseImplementation22222222-2222-2222-2222-2222222222221An adversary can gain long term, persistent access to an Azure Postgres DB instance through the compromise of local user account password(s)falseEAn adversary can gain unauthorized access to {target.Name} due to weak account policytarget is 'SE.DS.TMCore.AzureSQLDWDB'TH156UserThreatDescriptionfalseAn adversary can gain unauthorized access to {target.Name} due to weak account policy22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseWhen possible use Azure Active Directory Authentication for Connecting to SQL DW Database. Refer: <a href="https://aka.ms/tmt-th156a">https://aka.ms/tmt-th156a</a>. Ensure that least-privileged accounts are used to connect to SQL DW Database. Refer: <a href="https://aka.ms/tmt-th156b">https://aka.ms/tmt-th156b</a> and <a href="https://aka.ms/tmt-th156c">https://aka.ms/tmt-th156c</a>22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseImplementation22222222-2222-2222-2222-2222222222221An adversary can gain unauthorized access to {target.Name} due to weak account policyfalseEAn adversary can gain unauthorized access to {target.Name} instances due to weak network security configurationtarget is 'SE.DS.TMCore.AzureSQLDWDB' and not target.b8c8850c-979b-4db0-b536-9aa364b7e6a2 is 'Allow access from selected networks (excluding Azure)'TH157UserThreatDescriptionfalseAn adversary can gain unauthorized access to Azure SQL DW DB instances due to weak network security configuration22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseRestrict access to Azure SQL DW DB instances by configuring server-level firewall rules to permit connections from selected networks (e.g. a virtual network or a custom set of IP addresses) where possible. Refer: <a href="https://aka.ms/tmt-th157">https://aka.ms/tmt-th157</a>.22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseImplementation22222222-2222-2222-2222-2222222222221An adversary can gain unauthorized access to Azure SQL DW DB instances due to weak network security configurationfalseTAn adversary can read confidential data or tamper with it due to weak connection string configuration at {target.Name} target is 'SE.DS.TMCore.AzureSQLDWDB'TH158UserThreatDescriptionfalseAn adversary can read confidential data or tamper with it due to weak connection string configuration22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseClients connecting to a Azure SQL DW DB instance using a connection string should ensure that encryption is enabled and trusting the server certificate by default is disabled (e.g. encrypt=true and trustservercertificate=false are set). This configuration ensures that connections are encrypted only if there is a verifiable server certificate (otherwise the connection attempt fails). This helps protect against Man-In-The-Middle attacks. Refer: <a href="https://aka.ms/tmt-th158">https://aka.ms/tmt-th158</a>.22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseImplementation22222222-2222-2222-2222-2222222222221An adversary can read confidential data or tamper with it due to weak connection string configurationfalseIAn adversary having access to the storage container (e.g. physical access to the storage media) may read sensitive datatarget is 'SE.DS.TMCore.AzureSQLDWDB' and not target.d2ce181d-abae-448d-8ef4-9acdbeb839fe is 'True'TH159UserThreatDescriptionfalseAn adversary having access to the storage container (e.g. physical access to the storage media) may read sensitive data22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseEnable Transparent Data Encryption (TDE) on Azure SQL Data Warehouse Database instances to have data encrypted at rest. Refer: <a href="https://aka.ms/tmt-th159">https://aka.ms/tmt-th159</a>.22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseImplementation22222222-2222-2222-2222-2222222222221An adversary having access to the storage container (e.g. physical access to the storage media) may read sensitive datafalseEAn identity that is compromised may permit more privileges than intended to an adversary due to weak permission and role assignmentstarget is 'SE.DS.TMCore.AzureSQLDWDB'TH160UserThreatDescriptionfalseAn identity that is compromised may permit more privileges than intended to an adversary due to weak permission and role assignments22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseReview permission and role assignments to ensure users are granted the least privileges necessary. Refer: <a href="https://aka.ms/tmt-th160">https://aka.ms/tmt-th160</a>.22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseImplementation22222222-2222-2222-2222-2222222222221An identity that is compromised may permit more privileges than intended to an adversary due to weak permission and role assignmentsfalseRAn adversary can deny actions performed on {target.Name} due to lack of auditingtarget is 'SE.DS.TMCore.AzureSQLDWDB' and not target.cd2a18a2-cebd-4b0f-ae4c-964b190e84f2 is 'True'TH161UserThreatDescriptionfalseAn adversary can deny actions performed on {target.Name} due to lack of auditing22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseEnable auditing on Azure SQL DW DB instances to track and log database events. After configuring and customizing the audited events, enable threat detection to receive alerts on anomalous activities indicating potential security threats. Refer: <a href="https://aka.ms/tmt-th161">https://aka.ms/tmt-th161</a>.22222222-2222-2222-2222-2222222222222PriorityfalseMedium22222222-2222-2222-2222-2222222222221SDLPhasefalseImplementation22222222-2222-2222-2222-2222222222221An adversary can deny actions performed on {target.Name} due to lack of auditingfalseEAn adversary can gain long term, persistent access to {target.Name} through a compromise of its connection string(s)target is 'SE.DS.TMCore.AzureSQLDWDB'TH162UserThreatDescriptionfalseAn adversary can gain long term, persistent access to {target.Name} through a compromise of its connection string(s)22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseIt is recommended to rotate user account passwords (e.g. those used in connection strings) regularly, in accordance with your organization's policies. Store secrets in a secret storage solution (e.g. Azure Key Vault).22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseImplementation22222222-2222-2222-2222-2222222222221An adversary can gain long term, persistent access to {target.Name} through a compromise of its connection string(s)falseEAn adversary can gain unauthorized access to {target.Name} instances due to weak network security configurationtarget is 'SE.P.TMCore.AzureRedis' and not target.1bda806d-f9b6-4d4e-ab89-bf649f2c2ca5 is 'Allow access from selected networks'TH163UserThreatDescriptionfalseAn adversary can gain unauthorized access to {target.Name} instances due to weak network security configuration22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseRestrict access to Azure Redis Cache instances by configuring firewall rules to only permit connections from selected IP addresses or VNETs where possible. Refer: <a href="https://aka.ms/tmt-th163">https://aka.ms/tmt-th163</a>.22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseImplementation22222222-2222-2222-2222-2222222222221An adversary can gain unauthorized access to {target.Name} instances due to weak network security configurationfalseEAn adversary can gain long term, persistent access to {target.Name} instance through a compromise of its access key(s)target is 'SE.P.TMCore.AzureRedis'TH164UserThreatDescriptionfalseAn adversary can gain long term, persistent access to {target.Name} instance through a compromise of its access key(s)22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseIt is recommended to rotate user account passwords (e.g. those used in connection strings) regularly, in accordance with your organization's policies. Store secrets in a secret storage solution (e.g. Azure Key Vault).22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseImplementation22222222-2222-2222-2222-2222222222221An adversary can gain long term, persistent access to {target.Name} instance through a compromise of its access key(s)falseDAn adversary may block access to the application or API hosted on {target.Name} through a denial of service attacktarget is 'SE.P.TMCore.AzureAppServiceWebApp' or target is 'SE.P.TMCore.AzureAppServiceApiApp' or target is 'SE.P.TMCore.AzureAppServiceMobileApp'TH165UserThreatDescriptionfalseAn adversary may block access to the application or API hosted on {target.Name} through a denial of service attack22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseNetwork level denial of service mitigations are automatically enabled as part of the Azure platform (Basic Azure DDoS Protection). Refer: <a href="https://aka.ms/tmt-th165a">https://aka.ms/tmt-th165a</a>. Implement application level throttling (e.g. per-user, per-session, per-API) to maintain service availability and protect against DoS attacks. Leverage Azure API Management for managing and protecting APIs. Refer: <a href="https://aka.ms/tmt-th165b">https://aka.ms/tmt-th165b</a>. General throttling guidance, refer: <a href="https://aka.ms/tmt-th165c">https://aka.ms/tmt-th165c</a> 22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseImplementation22222222-2222-2222-2222-2222222222221An adversary may block access to the application or API hosted on {target.Name} through a denial of service attackfalseEAn adversary may gain long term persistent access to related resources through the compromise of an application identitytarget is 'SE.P.TMCore.AzureAppServiceWebApp' or target is 'SE.P.TMCore.AzureAppServiceApiApp' or target is 'SE.P.TMCore.AzureAppServiceMobileApp'TH166UserThreatDescriptionfalseAn adversary may gain long term persistent access to related resources through the compromise of an application identity22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseStore secrets in secret storage solutions where possible, and rotate secrets on a regular cadence. Use Managed Service Identity to create a managed app identity on Azure Active Directory and use it to access AAD-protected resources. Refer: <a href="https://aka.ms/tmt-th166">https://aka.ms/tmt-th166</a>22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseImplementation22222222-2222-2222-2222-2222222222221An adversary may gain long term persistent access to related resources through the compromise of an application identityfalseEAn adversary may gain unauthorized access to {target.Name} due to weak network configuration(target is 'SE.P.TMCore.AzureAppServiceWebApp' and not target.327ab565-9b38-4f6a-8171-6ab7deb2246b is 'Allow access from selected networks') or (target is 'SE.P.TMCore.AzureAppServiceApiApp' and not target.cb0fca77-c600-4622-b9a5-118107fcd9dd is 'Allow access from selected networks') or (target is 'SE.P.TMCore.AzureAppServiceMobileApp' and not target.9b54ed83-3970-475b-97a0-be7641051497 is 'Allow access from selected networks')TH167UserThreatDescriptionfalseAn adversary may gain unauthorized access to {target.Name} due to weak network configuration22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseRestrict access to Azure App Service to selected networks (e.g. IP whitelisting, VNET integrations). Refer: <a href="https://aka.ms/tmt-th167">https://aka.ms/tmt-th167</a>22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseImplementation22222222-2222-2222-2222-2222222222221An adversary may gain unauthorized access to {target.Name} due to weak network configurationfalseIAn adversary can achieve remote code execution on a server hosting an application or API by exploiting JSON deserialization logic(source is 'GE.EI' or source is 'SE.EI.TMCore.Browser') and ((target is 'SE.P.TMCore.AzureAppServiceWebApp' and target.d69db950-2372-4bd3-8328-f751f0b04c03 is 'True') or (target is 'SE.P.TMCore.AzureAppServiceApiApp' and target.0945adcf-1cfd-432f-8032-05391ab62336 is 'True') or (target is 'SE.P.TMCore.AzureAppServiceMobileApp' and target.015d94e3-d54e-4c09-9ce2-2731a0dc86f0 is 'True'))TH168UserThreatDescriptionfalseAn adversary can achieve remote code execution on a server hosting an application or API by exploiting JSON deserialization logic22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseEnsure serialized objects from untrusted sources are not being deserialized, or handle objects that have been serialized using a serializer that only permits primitive data types. Refer: <a href="https://aka.ms/tmt-th168">https://aka.ms/tmt-th168</a>22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseImplementation22222222-2222-2222-2222-2222222222221An adversary can achieve remote code execution on a server hosting an application or API by exploiting JSON deserialization logicfalseIAn adversary can achieve remote code execution on a server hosting an application or API by exploiting XML parsing logic or through XSLT scripting(source is 'GE.EI' or source is 'SE.EI.TMCore.Browser') and ((target is 'SE.P.TMCore.AzureAppServiceWebApp' and target.049c845a-28c2-46f8-bda2-971ff7df9bd4 is 'True') or (target is 'SE.P.TMCore.AzureAppServiceApiApp' and target.0eb10857-97b7-4c8c-8fdd-c289b7921a7e is 'True') or (target is 'SE.P.TMCore.AzureAppServiceMobileApp' and target.6c7ab607-e310-4d74-aa5b-397d87f02ee9 is 'True'))TH169UserThreatDescriptionfalseAn adversary can achieve remote code execution on a server hosting an application or API by exploiting XML parsing logic or through XSLT scripting22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseDisable XSLT scripting for all transforms using untrusted style sheets. Refer: <a href="https://aka.ms/tmt-th169a">https://aka.ms/tmt-th169a</a>. Disable DTD processing and external entity resolution on XML parsers to protect against XXE attacks. Refer: <a href="https://aka.ms/tmt-th169b">https://aka.ms/tmt-th169b</a>, <a href="https://aka.ms/tmt-th169c">https://aka.ms/tmt-th169c</a>, <a href="https://aka.ms/tmt-th169d">https://aka.ms/tmt-th169d</a> and <a href="https://aka.ms/tmt-th169e">https://aka.ms/tmt-th169e</a>22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseImplementation22222222-2222-2222-2222-2222222222221An adversary can achieve remote code execution on a server hosting an application or API by exploiting XML parsing logic or through XSLT scriptingfalseIAttacker can steal user session cookies due to insecure cookie attributessource is 'SE.EI.TMCore.Browser' and (target is 'SE.P.TMCore.AzureAppServiceWebApp' or target is 'SE.P.TMCore.AzureAppServiceApiApp' or target is 'SE.P.TMCore.AzureAppServiceMobileApp')TH170UserThreatDescriptionfalseAttacker can steal user session cookies due to insecure cookie attributes22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseApplications available over HTTPS must use secure cookies. Refer: <a href="https://aka.ms/tmt-th170a">https://aka.ms/tmt-th170a</a>. All HTTP based applications should specify http only for cookie definition. Refer: <a href="https://aka.ms/tmt-th170b">https://aka.ms/tmt-th170b</a> and <a href="https://aka.ms/tmt-th170c">https://aka.ms/tmt-th170c</a>22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseImplementation22222222-2222-2222-2222-2222222222221Attacker can steal user session cookies due to insecure cookie attributesfalseEAn adversary may get access to a user's session due to improper logout from ADFSsource is 'SE.P.TMCore.ADFS' and (target is 'SE.P.TMCore.AzureAppServiceWebApp' or target is 'SE.P.TMCore.AzureAppServiceApiApp' or target is 'SE.P.TMCore.AzureAppServiceMobileApp')TH171UserThreatDescriptionfalseAn adversary may get access to a user's session due to improper logout from ADFS22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseImplement proper logout using WsFederation methods when using ADFS. Refer: <a href="https://aka.ms/tmt-th171">https://aka.ms/tmt-th171</a>22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseImplementation22222222-2222-2222-2222-2222222222221An adversary may get access to a user's session due to improper logout from ADFSfalseEAn adversary may get access to a user's session due to improper logout from Azure ADsource is 'SE.P.TMCore.AzureAD' and (target is 'SE.P.TMCore.AzureAppServiceWebApp' or target is 'SE.P.TMCore.AzureAppServiceApiApp' or target is 'SE.P.TMCore.AzureAppServiceMobileApp')TH172UserThreatDescriptionfalseAn adversary may get access to a user's session due to improper logout from Azure AD22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseImplement proper logout using ADAL methods when using Azure AD. Refer: <a href="https://aka.ms/tmt-th172">https://aka.ms/tmt-th172</a>22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseImplementation22222222-2222-2222-2222-2222222222221An adversary may get access to a user's session due to improper logout from Azure ADfalseRAn adversary can deny performing actions against {target.Name} due to lack of auditing, leading to repudiation issues(source is 'GE.EI' or source is 'SE.EI.TMCore.Browser') and (target is 'SE.P.TMCore.AzureAppServiceWebApp' or target is 'SE.P.TMCore.AzureAppServiceApiApp' or target is 'SE.P.TMCore.AzureAppServiceMobileApp')TH173UserThreatDescriptionfalseAn adversary can deny performing actions against {target.Name} due to lack of auditing, leading to repudiation issues22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseImplement application level auditing and logging, especially for sensitive operations, like accessing secrets from secrets storage solutions. Other examples include user management events like successful and failed user logins, password resets, password changes, account lockouts and user registrations.22222222-2222-2222-2222-2222222222222PriorityfalseMedium22222222-2222-2222-2222-2222222222221SDLPhasefalseImplementation22222222-2222-2222-2222-2222222222221An adversary can deny performing actions against {target.Name} due to lack of auditing, leading to repudiation issuesfalseIAn adversary can fingerprint an Azure web application or API by leveraging server header information(source is 'GE.EI' or source is 'SE.EI.TMCore.Browser') and (target is 'SE.P.TMCore.AzureAppServiceWebApp' or target is 'SE.P.TMCore.AzureAppServiceApiApp' or target is 'SE.P.TMCore.AzureAppServiceMobileApp')TH174UserThreatDescriptionfalseAn adversary can fingerprint an Azure web application or API by leveraging server header information22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseRemove standard server headers to avoid fingerprinting. Refer: <a href="https://aka.ms/tmt-th174a">https://aka.ms/tmt-th174a</a> and <a href="https://aka.ms/tmt-th174b">https://aka.ms/tmt-th174b</a>22222222-2222-2222-2222-2222222222222PriorityfalseMedium22222222-2222-2222-2222-2222222222221SDLPhasefalseImplementation22222222-2222-2222-2222-2222222222221An adversary can fingerprint an Azure web application or API by leveraging server header informationfalseTAn adversary can read sensitive data by sniffing or intercepting traffic to {target.Name}source is 'SE.EI.TMCore.Browser' and (target is 'SE.P.TMCore.AzureAppServiceWebApp' or target is 'SE.P.TMCore.AzureAppServiceApiApp' or target is 'SE.P.TMCore.AzureAppServiceMobileApp')TH175UserThreatDescriptionfalseAn adversary can read sensitive data by sniffing or intercepting traffic to {target.Name}22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseConfigure SSL certificate for custom domain in Azure App Service. Force all HTTP traffic to the app service to be over HTTPS by enabling the HTTPS only option on the instance. Refer: <a href="https://aka.ms/tmt-th175a">https://aka.ms/tmt-th175a</a> and <a href="https://aka.ms/tmt-th175b">https://aka.ms/tmt-th175b</a>. Enable HTTP Strict Transport Security (HSTS). Refer: <a href="https://aka.ms/tmt-th175c">https://aka.ms/tmt-th175c</a>22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseImplementation22222222-2222-2222-2222-2222222222221An adversary can read sensitive data by sniffing or intercepting traffic to {target.Name}falseEAn adversary may perform action(s) on behalf of another user due to lack of controls against cross domain requests(target is 'SE.P.TMCore.AzureAppServiceWebApp' and target.f6b0309d-2020-4c3f-838f-5ab8ea0d2194 is 'False') or (target is 'SE.P.TMCore.AzureAppServiceApiApp' and target.3f4a2250-9087-44c1-9fb7-61e9eb1e4df7 is 'False') or (target is 'SE.P.TMCore.AzureAppServiceMobileApp' and target.6ddbac5e-2e11-4b88-b917-587749ea4721 is 'False')target is 'SE.P.TMCore.AzureAppServiceWebApp' or target is 'SE.P.TMCore.AzureAppServiceApiApp' or target is 'SE.P.TMCore.AzureAppServiceMobileApp'TH176UserThreatDescriptionfalseAn adversary may perform action(s) on behalf of another user due to lack of controls against cross domain requests22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseEnsure that only trusted origins are allowed if CORS is being used. Refer: <a href="https://aka.ms/tmt-th176">https://aka.ms/tmt-th176</a>22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseImplementation22222222-2222-2222-2222-2222222222221An adversary may perform action(s) on behalf of another user due to lack of controls against cross domain requestsfalseSAn adversary may be able to perform action(s) on behalf of another user due to lack of controls against cross domain requestssource is 'SE.EI.TMCore.Browser' and (target is 'SE.P.TMCore.AzureAppServiceWebApp' or target is 'SE.P.TMCore.AzureAppServiceApiApp' or target is 'SE.P.TMCore.AzureAppServiceMobileApp')TH177UserThreatDescriptionfalseAn adversary may be able to perform action(s) on behalf of another user due to lack of controls against cross domain requests22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseEnsure that authenticated pages incorporate UI Redressing or clickjacking defences. Refer: <a href="https://aka.ms/tmt-th177a">https://aka.ms/tmt-th177a</a>. Mitigate against Cross-Site Request Forgery (CSRF) attacks. Refer: <a href="https://aka.ms/tmt-th177b">https://aka.ms/tmt-th177b</a> and <a href="https://aka.ms/tmt-th177c">https://aka.ms/tmt-th177c</a>22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseImplementation22222222-2222-2222-2222-2222222222221An adversary may be able to perform action(s) on behalf of another user due to lack of controls against cross domain requestsfalseSAn adversary may spoof the service or service endpoints by leveraging stale CNAME DNS records and executing a subdomain hijack attacktarget is 'SE.P.TMCore.AzureTrafficManager'TH178UserThreatDescriptionfalseAn adversary may spoof the service or service endpoints by leveraging stale CNAME DNS records and executing a subdomain hijack attack22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseAddress stale CNAME DNS records mapping custom domain names to the domain name of the Azure Traffic Manager instance. In some cases, deleting the stale CNAME records may be sufficient, while in other cases, the domain name of the Azure Traffic Manager instance should be kept to prevent subdomain hijack attacks. Refer: <a href="https://aka.ms/tmt-th178 ">https://aka.ms/tmt-th178 </a>22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseImplementation22222222-2222-2222-2222-2222222222221An adversary may spoof the service or service endpoints by leveraging stale CNAME DNS records and executing a subdomain hijack attackfalseEAn adversary can gain unauthorized access to Azure Key Vault instances due to weak network security configuration.target is 'SE.DS.TMCore.AzureKeyVault' and not target.cd610fb8-4fbd-49c0-966f-8b4634b39262 is 'Allow access from selected networks'TH179UserThreatDescriptionfalseAn adversary can gain unauthorized access to Azure Key Vault instances due to weak network security configuration.22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseRestrict access to Azure Key Vault instances by configuring firewall rules to permit connections from selected networks (e.g. a virtual network or a custom set of IP addresses).For Key Vault client applications behind a firewall trying to access a Key Vault instance, see best practices mentioned here: <a href="https://aka.ms/tmt-th179 ">https://aka.ms/tmt-th179 </a>22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseImplementation22222222-2222-2222-2222-2222222222221An adversary can gain unauthorized access to Azure Key Vault instances due to weak network security configuration.falseRAn adversary can deny actions performed on {target.Name} due to a lack of auditing. target is 'SE.DS.TMCore.AzureKeyVault' and not target.78bf9482-5267-41c6-84fd-bac2fb6ca0b9 is 'True'TH180UserThreatDescriptionfalseAn adversary can deny actions performed on {target.Name} due to a lack of auditing. 22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseEnable audit logging on Azure Key Vault instances to monitor how and when the instances are access, and by whom. Use standard Azure access controls to restrict access to the logs. Refer : <a href="https://aka.ms/tmt-th180 ">https://aka.ms/tmt-th180 </a>22222222-2222-2222-2222-2222222222222PriorityfalseMedium22222222-2222-2222-2222-2222222222221SDLPhasefalseImplementation22222222-2222-2222-2222-2222222222221An adversary can deny actions performed on {target.Name} due to a lack of auditing. falseEAn adversary may gain unauthorized access to manage {target.Name} due to weak authorization rules. target is 'SE.DS.TMCore.AzureKeyVault'TH181UserThreatDescriptionfalseAn adversary may gain unauthorized access to manage {target.Name} due to weak authorization rules.22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseAccess to the Azure Key Vault management plane should be restricted by choosing appropriate Role-Based Access Control (RBAC) roles and privileges in accordance with the principle of least privilege. Over permissive or weak authorization rules may potentially permit data plane access (e.g. a user with Contribute (RBAC) permissions to Key Vault management plane may grant themselves access to the data plane by setting the Azure Key Vault access policy). Refer : <a href="https://aka.ms/tmt-th181 ">https://aka.ms/tmt-th181 </a>22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseImplementation22222222-2222-2222-2222-2222222222221An adversary may gain unauthorized access to manage {target.Name} due to weak authorization rules.falseEAn adversary may gain unauthorized access to {target.Name} secrets due to weak authorization rules target is 'SE.DS.TMCore.AzureKeyVault'TH182UserThreatDescriptionfalseAn adversary may gain unauthorized access to {target.Name} secrets due to weak authorization rules22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseLimit Azure Key Vault data plane access by configuring strict access policies. Grant users, groups and applications the ability to perform only the necessary operations against keys or secrets in a Key Vault instance. Follow the principle of least privilege and grant privileges only as needed. Refer : <a href="https://aka.ms/tmt-th181 ">https://aka.ms/tmt-th181 </a>22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseImplementation22222222-2222-2222-2222-2222222222221An adversary may gain unauthorized access to {target.Name} secrets due to weak authorization rulesfalseEAn adversary can abuse poorly managed service principal Certificate. An adversary may gain unauthorized access to {target.Name} due to compromise of User or Service Principal . target is 'SE.DS.TMCore.AzureKeyVault' and target.ae94fa17-596d-476e-a283-0afc166dcf26 is 'Service or User Principal and Certificate'TH183UserThreatDescriptionfalseAn adversary can abuse poorly managed service principal Certificate. An adversary may gain unauthorized access to {target.Name} due to compromise of User or Service Principal .22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseEnsure secure management and storage of Azure Key Vault Service/User Principal certificate. It is recommended to rotate service principal certificate regularly, in accordance with organizational policies. If supported , use managed identities for Azure resources and details can be found here. Refer : <a href="https://aka.ms/tmt-th183 ">https://aka.ms/tmt-th183 </a>22222222-2222-2222-2222-2222222222222PriorityfalseMedium22222222-2222-2222-2222-2222222222221SDLPhasefalseImplementation22222222-2222-2222-2222-2222222222221An adversary can abuse poorly managed service principal Certificate. An adversary may gain unauthorized access to {target.Name} due to compromise of User or Service Principal . falseEAn adversary can abuse poorly managed service principal secret. An adversary may gain unauthorized access to {target.Name} due to compromise of Service Principal Secret . target is 'SE.DS.TMCore.AzureKeyVault' and target.ae94fa17-596d-476e-a283-0afc166dcf26 is 'Service or User Principal and Secret' TH184UserThreatDescriptionfalseAn adversary can abuse poorly managed service principal secret. An adversary may gain unauthorized access to {target.Name} due to compromise of Service Principal Secret .22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseUse managed identities for Azure resources and details can be found here at <a href="https://aka.ms/tmt-th183 ">https://aka.ms/tmt-th183</a>. If managed identities is not supported , use Service/User Principal and Certificate. If none of the above options are feasible, please ensure secure management and storage of Azure Key Vault Service/User Principal secret . It is recommended to rotate service/user principal secret regularly, in accordance with organizational policies.22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseImplementation22222222-2222-2222-2222-2222222222221An adversary can abuse poorly managed service principal secret. An adversary may gain unauthorized access to {target.Name} due to compromise of Service Principal Secret . falseEAn adversary can abuse poorly managed authentication/access policies. An adversary may gain unauthorized access to {target.Name} due to compromise of secret/certificate used to authenticate to {target.Name} .target is 'SE.DS.TMCore.AzureKeyVault' and target.ae94fa17-596d-476e-a283-0afc166dcf26 is 'Select' TH185UserThreatDescriptionfalseAn adversary can abuse poorly managed authentication/access policies. An adversary may gain unauthorized access to {target.Name} due to compromise of secret/certificate used to authenticate to {target.Name} 22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseUse managed identities for Azure resources and details can be found here at <a href="https://aka.ms/tmt-th183 ">https://aka.ms/tmt-th183 </a>. If managed identities is not supported , use Service/User Principal and Certificate. If none of the above options are feasible, please ensure secure management and storage of Azure Key Vault Service/User Principal secret . It is recommended to rotate service/user principal secret regularly, in accordance with organizational policies.22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseImplementation22222222-2222-2222-2222-2222222222221An adversary can abuse poorly managed authentication/access policies. An adversary may gain unauthorized access to {target.Name} due to compromise of secret/certificate used to authenticate to {target.Name} . falseDAn adversary may attempt to delete key vault or key vault object causing business disruption. target is 'SE.DS.TMCore.AzureKeyVault'TH186UserThreatDescriptionfalseAn adversary may attempt to delete key vault or key vault object causing business disruption. 22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseKey Vault's soft delete feature allows recovery of the deleted vaults and vault objects, known as soft-delete . Soft deleted resources are retained for a set period of time, 90 days. Refer : <a href="https://aka.ms/tmt-th186 ">https://aka.ms/tmt-th186 </a>22222222-2222-2222-2222-2222222222222PriorityfalseLow22222222-2222-2222-2222-2222222222221SDLPhasefalseImplementation22222222-2222-2222-2222-2222222222221An adversary may attempt to delete key vault or key vault object causing business disruption. falseEAn adversary may gain unauthorized access to manage {target.Name} due to weak authorization rulestarget is 'SE.P.TMCore.ALA'TH187UserThreatDescriptionfalseAn adversary may gain unauthorized access to manage {target.Name} due to weak authorization rules22222222-2222-2222-2222-2222222222220PossibleMitigationsfalse + Access to the Azure Logic Apps management plane should be restricted by assigning the appropriate Role-Based Access Control (RBAC) roles to only those needing the privileges. Follow the principle of least privilege.  + Refer : <a href="https://aka.ms/tmt-th187 ">https://aka.ms/tmt-th187 </a> + 22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseImplementation22222222-2222-2222-2222-2222222222221An adversary may gain unauthorized access to manage {target.Name} due to weak authorization rulesfalseEAn adversary may gain unauthorized access to {target.Name} workflow run history data due to weak network configurationtarget is 'SE.P.TMCore.ALA' and not target.0b0ab9bc-a582-4509-a6c4-8d56de65661e is 'Specific IP'TH188UserThreatDescriptionfalseAn adversary may gain unauthorized access to {target.Name} workflow run history data due to weak network configuration22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseLimit Azure Logic Apps data plane access to workflow run history data by only allowing requests from specific IP address ranges. Grant access only as necessary, adhering to the principle of least privilege. Refer : <a href="https://aka.ms/tmt-th188 ">https://aka.ms/tmt-th188 </a>22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseDesign22222222-2222-2222-2222-2222222222221An adversary may gain unauthorized access to {target.Name} workflow run history data due to weak network configurationfalseEAn adversary may gain unauthorized access to {target.Name} triggers/actions inputs or outputs by workflow run history datatarget is 'SE.P.TMCore.ALA' and not target.b1724997-7ae6-4b30-a001-9c5b42d9d1d1 is 'No'TH189UserThreatDescriptionfalseAn adversary may gain unauthorized access to {target.Name} triggers/actions inputs or outputs by workflow run history data22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseEnable secure inputs or outputs on the trigger or action to prevent sensitive data from being logged into run history. Refer : <a href="https://aka.ms/tmt-th189 ">https://aka.ms/tmt-th189 </a>22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseDesign22222222-2222-2222-2222-2222222222221An adversary may gain unauthorized access to {target.Name} triggers/actions inputs or outputs by workflow run history datafalseEAn adversary may gain unauthorized access to {target.Name} trigger due to weak controls on the triggertarget is 'SE.P.TMCore.ALA' and not target.5afb52dc-dffb-4319-aa22-523f78ee3845 is 'No'TH190UserThreatDescriptionfalseAn adversary may gain unauthorized access to {target.Name} trigger due to weak controls on the trigger22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseLimit access to invoke the trigger by Logic Apps Shared Access Signatures ( SAS) keys and callback URLs. Refer : <a href="https://aka.ms/tmt-th190 ">https://aka.ms/tmt-th190</a>22222222-2222-2222-2222-2222222222222PriorityfalseMedium22222222-2222-2222-2222-2222222222221SDLPhasefalseDesign22222222-2222-2222-2222-2222222222221An adversary may gain unauthorized access to {target.Name} trigger due to weak controls on the triggerfalseEAn adversary may gain unauthorized access to trigger {target.Name} workflows due to weak network configuration  target is 'SE.P.TMCore.ALA' and ( target.d488c23c-1667-45a1-994b-f56f2655727b is 'Allow any IP inbound' or target.d488c23c-1667-45a1-994b-f56f2655727b is 'Select')TH191UserThreatDescriptionfalseAn adversary may gain unauthorized access to trigger {target.Name} workflows due to weak network configuration 22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseRestrict calls to Azure Logic Apps on a network level, only permitting specific clients (belonging to a set of IP addresses or IP address range) to trigger workflows. Refer : <a href="https://aka.ms/tmt-th191 ">https://aka.ms/tmt-th191</a>22222222-2222-2222-2222-2222222222222PriorityfalseMedium22222222-2222-2222-2222-2222222222221SDLPhasefalseDesign22222222-2222-2222-2222-2222222222221An adversary may gain unauthorized access to trigger {target.Name} workflows due to weak network configuration falseIAn adversary may read sensitive workflow parameters due to improper handling and management of workflow parameters and inputs target is 'SE.P.TMCore.ALA'TH192UserThreatDescriptionfalseAn adversary may read sensitive workflow parameters due to improper handling and management of workflow parameters and inputs 22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseDefine resource parameters and leverage Azure Logic Apps workflow definition language, such as the @parameters() operation, to access resource parameter values at runtime. Use the securestring parameter type to better protect when and how parameter values can be accessed. For sensitive parameters (e.g. secrets), use Azure Key Vault to store and retrieve secrets when needed. Refer : <a href="https://aka.ms/tmt-th192 ">https://aka.ms/tmt-th192</a>22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseImplementation22222222-2222-2222-2222-2222222222221An adversary may read sensitive workflow parameters due to improper handling and management of workflow parameters and inputs falseEAn adversary can abuse poorly managed credentials or secrets used to access other resources in AAD tenantstarget is 'SE.P.TMCore.ALA'TH193UserThreatDescriptionfalseAn adversary can abuse poorly managed credentials or secrets used to access other resources in AAD tenants22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseUse managed identities , if possible , for your logic apps to connect to different resources managed in AAD tenant.  Refer : <a href="https://aka.ms/tmt-th193 ">https://aka.ms/tmt-th193</a>22222222-2222-2222-2222-2222222222222PriorityfalseMedium22222222-2222-2222-2222-2222222222221SDLPhasefalseImplementation22222222-2222-2222-2222-2222222222221An adversary can abuse poorly managed credentials or secrets used to access other resources in AAD tenants.falseEAn adversary may gain unauthorized access to run any action on {target.Name} due to weak authorization rulestarget is 'SE.P.TMCore.ADE'TH194UserThreatDescriptionfalseAn adversary may gain unauthorized access to run any action on {target.Name} due to weak authorization rules22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseEnsure access to run any action on a Kusto resource is restricted by assigning the appropriate Role-Based Access Control (RBAC) roles to only those needing the privileges. Follow the principle of least privilege. Security roles define which security principals (users and applications) can have permissions to operate on a secured resource (such as a database or a table), and what operations are permitted. Refer : 1) <a href="https://aka.ms/tmt-th194 ">https://aka.ms/tmt-th194 </a> 2)<a href="https://aka.ms/tmt-th194a ">https://aka.ms/tmt-th194a </a>22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseImplementation22222222-2222-2222-2222-2222222222221An adversary may gain unauthorized access to run any action on {target.Name} due to weak authorization rulesfalseISecret information should not be logged in {target.Name}target is 'SE.P.TMCore.ADE'TH195UserThreatDescriptionfalseSecret information should not be logged in {target.Name}22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseEnsure any secret information like passwords , SAS Tokens , refresh tokens etc are not logged in Azure Data Explorer.22222222-2222-2222-2222-2222222222222PriorityfalseHigh22222222-2222-2222-2222-2222222222221SDLPhasefalseImplementation22222222-2222-2222-2222-2222222222221Secret information should not be logged in {target.Name}falseISensitive information might get disclosed while querying {target.Name}target is 'SE.P.TMCore.ADE'TH196UserThreatDescriptionfalseSensitive information might get disclosed while querying {target.Name}22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseRestrictedViewAccess policy can be enabled on tables in database which contain sensitive information and only principals with "UnrestrictedViewer" role in the database can query that data.Refer : <a href="https://aka.ms/tmt-th196 ">https://aka.ms/tmt-th196 </a>22222222-2222-2222-2222-2222222222222PriorityfalseMedium22222222-2222-2222-2222-2222222222221SDLPhasefalseImplementation22222222-2222-2222-2222-2222222222221Sensitive information might get disclosed while querying {target.Name}falseEAn adversary can run malicious Kusto queries on {target.Name} if user provided input is used in non-parameterised queriestarget is 'SE.P.TMCore.ADE'TH197UserThreatDescriptionfalseAn adversary can run malicious Kusto queries on {target.Name} if user provided input is used in non-parameterised queries22222222-2222-2222-2222-2222222222220PossibleMitigationsfalsePlease use query parameters to protect against injection attacks.Refer : <a href="https://aka.ms/tmt-th197 ">https://aka.ms/tmt-th197 </a>22222222-2222-2222-2222-2222222222222PriorityfalseMedium22222222-2222-2222-2222-2222222222221SDLPhasefalseImplementation22222222-2222-2222-2222-2222222222221An adversary can run malicious Kusto queries on {target.Name} if user provided input is used in non-parameterised queriesfalseIAn adversary can gain access to unencrypted sensitive data stored in {target.Name} clustertarget is 'SE.P.TMCore.ADE'TH198UserThreatDescriptionfalseAn adversary can gain access to unencrypted sensitive data stored in {target.Name} cluster22222222-2222-2222-2222-2222222222220PossibleMitigationsfalseEnabling encryption at rest on your cluster provides data protection for stored data (at rest). Refer : <a href="https://aka.ms/tmt-th198 ">https://aka.ms/tmt-th198 </a>22222222-2222-2222-2222-2222222222222PriorityfalseMedium22222222-2222-2222-2222-2222222222221SDLPhasefalseImplementation22222222-2222-2222-2222-2222222222221An adversary can gain access to unencrypted sensitive data stored in {target.Name} cluster
\ No newline at end of file diff --git a/Directory.Packages.props b/Directory.Packages.props new file mode 100644 index 0000000..e470650 --- /dev/null +++ b/Directory.Packages.props @@ -0,0 +1,17 @@ + + + true + + + + + + + + + + + + + + \ No newline at end of file diff --git a/LICENSE b/LICENSE index 9e841e7..7965606 100644 --- a/LICENSE +++ b/LICENSE @@ -18,4 +18,4 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE + SOFTWARE \ No newline at end of file diff --git a/README.md b/README.md index 5cd7cec..a70b98e 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,32 @@ -# Project +# Microsoft Teams Call Record Insights -> This repo has been populated by an initial template to help get you started. Please -> make sure to update the content to build a great experience for community-building. +## What is Call Record Insights? -As the maintainer of this project, please make a few updates: +Call Record Insights is a turnkey application template for retrieving, parsing, flattening, and storing Microsoft Teams Call Records retrieved via Graph API. -- Improving this README.MD file to provide a great experience -- Updating SUPPORT.MD with content about this project's support experience -- Understanding the security reporting process in SECURITY.MD -- Remove this section from the README +This application enables you to retrieve your tenant's call records, parse them into a meaningful format and store them in Cosmos DB and Kusto without writing any code yourself. + +Because this solution uses Cosmos DB it is highly scalable and because it uses Kusto it is very friendly to application development and deep data analysis. + +The solution is fully deployed within your own tenant. All data processing and data storage is done in whichever tenant you deploy the application. + +1. [High Level Architecture](./docs/high-level-architecture.md) + +1. [Requirements](./docs/requirements.md) + +1. [Deployment](./docs/deployment.md) + +1. [Validation & Verification](./docs/deployment.md#deployment-validation--verification) + +1. [Admin Functions](./docs/admin-functions.md) + +1. [CosmosDB, Kusto Functions, Views and Queries](./docs/data-explorer-functions-views-queries.md) + +1. [Configuration Settings](./docs/function-configuration-settings.md) + +1. [Multi Tenant](./docs/multi-tenant-deployment.md) + +1. [Troubleshooting](./docs/troubleshooting.md) ## Contributing @@ -30,4 +48,4 @@ This project may contain trademarks or logos for projects, products, or services trademarks or logos is subject to and must follow [Microsoft's Trademark & Brand Guidelines](https://www.microsoft.com/en-us/legal/intellectualproperty/trademarks/usage/general). Use of Microsoft trademarks or logos in modified versions of this project must not cause confusion or imply Microsoft sponsorship. -Any use of third-party trademarks or logos are subject to those third-party's policies. +Any use of third-party trademarks or logos are subject to those third-party's policies. \ No newline at end of file diff --git a/SECURITY.md b/SECURITY.md index b3c89ef..96d73bc 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -38,4 +38,4 @@ We prefer all communications to be in English. Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://aka.ms/security.md/cvd). - + \ No newline at end of file diff --git a/SUPPORT.md b/SUPPORT.md index 291d4d4..dace74c 100644 --- a/SUPPORT.md +++ b/SUPPORT.md @@ -22,4 +22,4 @@ CHANNEL. WHERE WILL YOU HELP PEOPLE?**. ## Microsoft Support Policy -Support for this **PROJECT or PRODUCT** is limited to the resources listed above. +Support for this **PROJECT or PRODUCT** is limited to the resources listed above. \ No newline at end of file diff --git a/deploy/bicep/GraphChangeNotificationSubnets.jsonc b/deploy/bicep/GraphChangeNotificationSubnets.jsonc new file mode 100644 index 0000000..3eb8c68 --- /dev/null +++ b/deploy/bicep/GraphChangeNotificationSubnets.jsonc @@ -0,0 +1,84 @@ +// See: https://learn.microsoft.com/en-us/microsoft-365/enterprise/additional-office365-ip-addresses-and-urls for more information +{ + "AzureCloud": [ + "52.159.23.209/32", + "52.159.17.84/32", + "13.78.204.0/32", + "52.147.213.251/32", + "52.147.213.181/32", + "20.127.53.125/32", + "70.37.95.92/32", + "70.37.95.11/32", + "70.37.92.195/32", + "20.9.36.45/32", + "20.9.35.166/32", + "20.9.36.128/32", + "20.96.21.67/32", + "20.69.245.215/32", + "104.46.117.15/32", + "137.135.11.161/32", + "137.135.11.116/32", + "20.253.156.113/32", + "52.159.107.50/32", + "52.159.107.4/32", + "52.159.124.33/32", + "20.98.68.182/32", + "20.98.68.57/32", + "20.98.68.200/32", + "20.171.81.121/32", + "20.25.189.138/32", + "20.171.82.192/32", + "52.142.114.29/32", + "52.142.115.31/32", + "20.223.139.245/32", + "51.124.75.43/32", + "51.124.73.177/32", + "104.40.209.182/32", + "20.199.102.157/32", + "20.199.102.73/32", + "20.216.150.67/32", + "20.91.212.211/32", + "20.91.212.136/32", + "20.91.213.57/32", + "20.44.210.83/32", + "20.44.210.146/32", + "20.212.153.162/32", + "40.80.232.177/32", + "40.80.232.118/32", + "52.231.196.24/32", + "20.48.12.75/32", + "20.48.11.201/32", + "20.89.108.161/32", + "104.215.13.23/32", + "104.215.6.169/32", + "20.89.240.165/32" + ], + "AzureUSGovernment": [ + "52.244.33.45/32", + "52.244.35.174/32", + "52.243.157.104/32", + "52.243.157.105/32", + "52.182.25.254/32", + "52.182.25.110/32", + "52.181.25.67/32", + "52.181.25.66/32", + "52.244.111.156/32", + "52.244.111.170/32", + "52.243.147.249/32", + "52.243.148.19/32", + "52.182.32.51/32", + "52.182.32.143/32", + "52.181.24.199/32", + "52.181.24.220/32" + ], + "AzureChinaCloud": [ + "42.159.72.35/32", + "42.159.72.47/32", + "42.159.180.55/32", + "42.159.180.56/32", + "40.125.138.23/32", + "40.125.136.69/32", + "40.72.155.199/32", + "40.72.155.216/32" + ] +} \ No newline at end of file diff --git a/deploy/bicep/configureKusto.bicep b/deploy/bicep/configureKusto.bicep new file mode 100644 index 0000000..06bb1e2 --- /dev/null +++ b/deploy/bicep/configureKusto.bicep @@ -0,0 +1,110 @@ +// Parameters +@description('The name of the Kusto cluster.') +param clusterName string + +@description('The name of the Cosmos DB account that will be used to store the call records.') +param cosmosAccountName string + +@description('The name of the Cosmos DB database that will be used to store the call records.') +param callRecordsDatabaseName string = 'callrecordinsights' + +@description('The name of the Cosmos DB container that will be used to store the call records.') +param callRecordsContainerName string = 'records' + +@description('The name of the Kusto database.') +param databaseName string = 'CallRecordInsights' + +@description('The name of the table to create.') +param tableName string = 'CallRecords' + +@description('The name of the view to create.') +param viewName string = '${tableName}View' + +@description('The name of the get call records function to create.') +param callRecordsFunctionName string = '${tableName}Func' + +param location string = resourceGroup().location + +param updateTag string = newGuid() + +// Existing Resources +resource kustoCluster 'Microsoft.Kusto/clusters@2022-12-29' existing = { + name: clusterName + resource database 'databases' existing = { + name: databaseName + } +} + +resource cosmosAccount 'Microsoft.DocumentDB/databaseAccounts@2023-09-15' existing = { + name: cosmosAccountName + resource database 'sqlDatabases' existing = { + name: callRecordsDatabaseName + resource container 'containers' existing = { + name: callRecordsContainerName + } + } +} + +// Deploy the table, view, and functions +resource table 'Microsoft.Kusto/clusters/databases/scripts@2022-12-29' = { + name: guid(tableName,'createtable') + parent: kustoCluster::database + properties: { + continueOnErrors: false + forceUpdateTag: updateTag + scriptContent: replace(replace(replace(loadTextContent('kustoScripts/CreateTable.kql'),'##TABLE_NAME##',tableName),'##VIEW_NAME##',viewName),'##FUNCTION_NAME##',callRecordsFunctionName) + } +} + +resource configure 'Microsoft.Kusto/clusters/databases/scripts@2022-12-29' = { + name: guid(tableName,'configuretable') + parent: kustoCluster::database + properties: { + continueOnErrors: false + forceUpdateTag: updateTag + scriptContent: replace(replace(replace(loadTextContent('kustoScripts/Configure.kql'),'##TABLE_NAME##',tableName),'##VIEW_NAME##',viewName),'##FUNCTION_NAME##',callRecordsFunctionName) + } + dependsOn: [ + table // Ensure the table is created before creating the view and function + ] +} + +// Assign the Cosmos DB Account Reader Role +resource assignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid(clusterName, tableName, 'fbdf93bf-df7d-467e-a4d2-9458aa1360c8') + properties: { + roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'fbdf93bf-df7d-467e-a4d2-9458aa1360c8') + principalId: kustoCluster.identity.principalId + } +} + +// Assign the Cosmos DB Data Reader Role +resource comsosAssignment 'Microsoft.DocumentDB/databaseAccounts/sqlRoleAssignments@2023-09-15' = { + name: guid(clusterName, tableName, '00000000-0000-0000-0000-000000000001') + parent: cosmosAccount + properties: { + roleDefinitionId: resourceId('Microsoft.DocumentDB/databaseAccounts/sqlRoleDefinitions', cosmosAccount.name, '00000000-0000-0000-0000-000000000001') + principalId: kustoCluster.identity.principalId + scope: replace(replace(cosmosAccount::database::container.id,'/sqlDatabases/','/dbs/'),'/containers/','/colls/') + } +} + +resource kustoIngestion 'Microsoft.Kusto/clusters/databases/dataConnections@2023-08-15' = { + name: '${tableName}Ingestion' + location: location + parent: kustoCluster::database + kind: 'CosmosDb' + properties: { + cosmosDbAccountResourceId: cosmosAccount.id + cosmosDbDatabase: cosmosAccount::database.properties.resource.id + cosmosDbContainer: cosmosAccount::database::container.properties.resource.id + managedIdentityResourceId: kustoCluster.id + tableName: tableName + mappingRuleName: 'CallRecordMappingJsonMapping' + } + dependsOn: [ + assignment // Ensure the assignments are done before creating the ingestion + comsosAssignment + configure // Ensure the table and mapping are created before creating the ingestion + ] +} diff --git a/deploy/bicep/deploy.bicep b/deploy/bicep/deploy.bicep new file mode 100644 index 0000000..03989d6 --- /dev/null +++ b/deploy/bicep/deploy.bicep @@ -0,0 +1,108 @@ +@minLength(3) +@maxLength(24) +param baseResourceName string = resourceGroup().name + +@allowed(['DevTest','Production','RestrictedProduction']) +param deploymentSize string = 'Production' + +@description('The Azure region that\'s right for you. Not every resource is available in every region.') +param location string = resourceGroup().location + +@description('The URL to the git repository to deploy.') +param gitRepoUrl string = 'https://github.com/Microsoft/CallRecordInsights.git' + +@description('The branch of the git repository to deploy.') +param gitBranch string = 'main' + +@description('The domain of the tenant that will be monitored for Call Records.') +param tenantDomain string + +@description('The name of the cosmos account to use.') +param cosmosAccountName string = '${baseResourceName}cdb' + +@description('The name of the database to store call records in the cosmos account.') +param cosmosCallRecordsDatabaseName string = 'callrecordinsights' + +@description('The name of the container to store call records in the cosmos account.') +param cosmosCallRecordsContainerName string = 'records' + +@description('The name of the existing Kusto cluster to use.') +param existingKustoClusterName string = 'NOEXISTINGKUSTOCLUSTER' + +@description('The name of the database in the Kusto cluster.') +param kustoCallRecordsDatabaseName string = 'CallRecordInsights' + +@description('The name of the table to store processed call records in the Kusto cluster.') +param kustoCallRecordsTableName string = 'CallRecords' + +@description('The GUID of the Graph Change Tracking Service Principal for the Subscription\'s tenant.') +@minLength(36) +@maxLength(36) +param graphChangeTrackingSPNObjectId string + +param useEventHubManagedIdentity bool = false + +module kustoDeploy 'deployKusto.bicep' = { + name: 'kustoDeploy' + params: { + deploymentType: deploymentSize + location: location + databaseName: kustoCallRecordsDatabaseName + existingKustoClusterName: existingKustoClusterName + } +} + +module cosmosDeploy 'deployCosmos.bicep' = { + name: 'cosmosDeploy' + params: { + baseResourceName: baseResourceName + location: location + daysToRetainData: 30 + accountName: cosmosAccountName + databaseName: cosmosCallRecordsDatabaseName + containerName: cosmosCallRecordsContainerName + } +} + +module functionDeploy 'deployFunction.bicep' = { + name: 'functionDeploy' + params: { + graphChangeTrackingAppObjectId: graphChangeTrackingSPNObjectId + teamsTenantDomainName: tenantDomain + baseResourceName: baseResourceName + location: location + deploymentType: deploymentSize + cosmosAccountName: cosmosDeploy.outputs.cosmosDbAccountName + callRecordsDatabaseName: cosmosDeploy.outputs.databaseName + callRecordsContainerName: cosmosDeploy.outputs.containerName + useGraphEventHubManagedIdentity: useEventHubManagedIdentity + } +} + +module kustoConfigure 'configureKusto.bicep' = { + name: 'kustoConfigure' + params: { + clusterName: kustoDeploy.outputs.Name + cosmosAccountName: cosmosDeploy.outputs.cosmosDbAccountName + callRecordsDatabaseName: cosmosDeploy.outputs.databaseName + callRecordsContainerName: cosmosDeploy.outputs.containerName + databaseName: kustoCallRecordsDatabaseName + tableName: kustoCallRecordsTableName + viewName: '${kustoCallRecordsTableName}View' + callRecordsFunctionName: '${kustoCallRecordsTableName}Func' + location: location + } +} + +module codeDeploy 'deployAppSource.bicep' = { + name: 'codeDeploy' + params: { + functionAppName: functionDeploy.outputs.functionName + gitRepoUrl: gitRepoUrl + gitBranch: gitBranch + } +} + +output appPrincipalprincipalId string = functionDeploy.outputs.functionAppIdentity.principalId +output functionName string = functionDeploy.outputs.functionName +output appDomain string = functionDeploy.outputs.appDomain diff --git a/deploy/bicep/deployAppSource.bicep b/deploy/bicep/deployAppSource.bicep new file mode 100644 index 0000000..8a77da9 --- /dev/null +++ b/deploy/bicep/deployAppSource.bicep @@ -0,0 +1,22 @@ +@description('The name of the Azure Function App to deploy to.') +param functionAppName string + +@description('The URL to the GitHub repository to deploy.') +param gitRepoUrl string = 'https://github.com/Microsoft/CallRecordInsights.git' + +@description('The branch of the GitHub repository to deploy.') +param gitBranch string = 'main' + +resource functionApp 'Microsoft.Web/sites@2022-09-01' existing = { + name: functionAppName +} + +resource sourceControl 'Microsoft.Web/sites/sourcecontrols@2022-09-01' = if (!empty(gitRepoUrl)) { + name: 'web' + parent: functionApp + properties: { + repoUrl: gitRepoUrl + branch: gitBranch + isManualIntegration: true + } +} diff --git a/deploy/bicep/deployCosmos.bicep b/deploy/bicep/deployCosmos.bicep new file mode 100644 index 0000000..37a01e3 --- /dev/null +++ b/deploy/bicep/deployCosmos.bicep @@ -0,0 +1,102 @@ +@description('The base name to use for the resources that will be provisioned.') +@minLength(3) +@maxLength(35) +param baseResourceName string = resourceGroup().name + +@description('The location to create the resources in.') +param location string = resourceGroup().location + +@description('The number of days to retain data in the Cosmos DB container.') +@minValue(1) +@maxValue(365) +param daysToRetainData int = 30 + +@description('The name of the Cosmos DB account to create. Must be between 3 and 44 characters long, and contain only lowercase letters, numbers, and hyphens and start with a letter or number.') +@minLength(3) +@maxLength(44) +param accountName string = '${baseResourceName}cdb' + +@description('The name of the Cosmos DB database to create.') +param databaseName string = 'callrecordinsights' + +@description('The name of the Cosmos DB container to create.') +param containerName string = 'records' + +resource cosmosDbAccount 'Microsoft.DocumentDB/databaseAccounts@2023-09-15' = { + name: toLower(accountName) + location: location + properties: { + databaseAccountOfferType: 'Standard' + locations: [ + { + locationName: location + failoverPriority: 0 + isZoneRedundant: false + } + ] + } + + resource database 'sqlDatabases' = { + name: databaseName + properties: { + resource: { + id: databaseName + } + options: { + autoscaleSettings: { + maxThroughput: 1000 + } + } + } + + resource container 'containers' = { + name: containerName + properties: { + resource: { + id: containerName + partitionKey: { + paths: [ + '/CallRecordTenantIdContext' + '/CallId' + ] + kind: 'MultiHash' + version: 2 + } + indexingPolicy: { + automatic: true + indexingMode: 'consistent' + includedPaths: [ + { path: '/CallRecordTenantIdContext/?' } + { path: '/CallId/?' } + { path: '/LastModifiedDateTimeOffset/?' } + ] + excludedPaths: [ + { path: '/*' } + ] + compositeIndexes: [ + [ + { + path: '/CallRecordTenantIdContext' + order: 'descending' + } + { + path: '/CallId' + order: 'descending' + } + { + path:'/LastModifiedDateTimeOffset' + order: 'descending' + } + ] + ] + } + defaultTtl: daysToRetainData * 24 * 60 * 60 + } + } + } + } +} + +output cosmosDbAccountName string = cosmosDbAccount.name +output databaseName string = cosmosDbAccount::database.name +output containerName string = cosmosDbAccount::database::container.name diff --git a/deploy/bicep/deployFunction.bicep b/deploy/bicep/deployFunction.bicep new file mode 100644 index 0000000..b0d83d3 --- /dev/null +++ b/deploy/bicep/deployFunction.bicep @@ -0,0 +1,555 @@ +// Parameters +@description('The object id of the Service Principal for the Graph Change Tracking Application.') +@minLength(36) +@maxLength(36) +param graphChangeTrackingAppObjectId string + +@description('The name of the tenant to monitor') +param teamsTenantDomainName string + +@description('The base name to use for the resources that will be provisioned. It must start with a letter and contain only letters and numbers. It must be globally unique.') +@minLength(3) +@maxLength(35) +param baseResourceName string = resourceGroup().name + +@description('Location for all resources.') +param location string = resourceGroup().location + +@description('The type of deployment. Production is a standard deployment. DevTest is a smaller deployment with no SLA.') +@allowed([ + 'Production' + 'RestrictedProduction' + 'DevTest' +]) +param deploymentType string = 'Production' + +@description('The name of the Cosmos DB account to create. Must be between 3 and 44 characters long, and contain only lowercase letters, numbers, and hyphens and start with a letter or number.') +@minLength(3) +@maxLength(44) +param cosmosAccountName string = '${baseResourceName}cdb' + +@description('The name of the cosmos database that contains the processed call records table.') +param callRecordsDatabaseName string = 'callrecordinsights' + +@description('The name of the cosmos container that contains the processed call records.') +param callRecordsContainerName string = 'records' + +param useSeparateKeyVaultForGraph bool = deploymentType != 'DevTest' + +param useGraphEventHubManagedIdentity bool = false + +// Variables +var tenantId = subscription().tenantId +var tenantDomain = teamsTenantDomainName + +var storageAccountName = 'callq${uniqueString(toLower(baseResourceName), toLower(tenantId))}' + +var downloadQueueName = '${toLower(callRecordsDatabaseName)}download' + +var keyvaultName = length('kv${baseResourceName}') > 24 ? substring('kv${baseResourceName}', 0, 24) : 'kv${baseResourceName}' + +var graphKeyVaultName = 'g${length(keyvaultName) > 23 ? substring(keyvaultName, 0, 23) : keyvaultName}' + +// T-Shirt sizing +var configurations = { + DevTest: { + serverfarm: { + sku: { + name: 'Y1' + // tier: 'Dynamic' + } + } + storage: { + sku: { + name: 'Standard_LRS' + } + properties: { + supportsHttpsTrafficOnly: true + allowBlobPublicAccess: false + minimumTlsVersion: 'TLS1_2' + } + } + eventHub: { + sku: { + name: 'Basic' + } + properties: { + disableLocalAuth: useGraphEventHubManagedIdentity + } + eventhubs: { + properties: { + messageRetentionInDays: 1 + } + } + } + functionApp: { + identity: { + type: 'SystemAssigned' + } + properties: { + clientAffinityEnabled: false + httpsOnly: true + siteConfig: { + alwaysOn: false + netFrameworkVersion: 'v6.0' + ftpsState: 'Disabled' + } + } + } + keyvault: { + properties: { + tenantId: subscription().tenantId + publicNetworkAccess: 'Enabled' + enableRbacAuthorization: true + sku: { + name: 'standard' + family: 'A' + } + } + } + } + Production: { + serverfarm: { + sku: { + name: 'Y1' + // tier: 'Dynamic' + } + } + storage: { + sku: { + name: 'Standard_GRS' + } + properties: { + supportsHttpsTrafficOnly: true + allowBlobPublicAccess: false + minimumTlsVersion: 'TLS1_2' + } + } + eventHub: { + sku: { + name: 'Basic' + } + properties: { + disableLocalAuth: useGraphEventHubManagedIdentity + } + eventhubs: { + properties: { + messageRetentionInDays: 1 + } + } + } + functionApp: { + identity: { + type: 'SystemAssigned' + } + properties: { + clientAffinityEnabled: false + httpsOnly: true + siteConfig: { + alwaysOn: false + netFrameworkVersion: 'v6.0' + ftpsState: 'Disabled' + } + } + } + keyvault: { + properties: { + tenantId: subscription().tenantId + publicNetworkAccess: 'Enabled' + enableRbacAuthorization: true + sku: { + name: 'standard' + family: 'A' + } + } + } + } + RestrictedProduction: { + serverfarm: { + sku: { + name: 'EP1' + // tier: 'Premium' + } + } + storage: { + sku: { + name: 'Standard_GRS' + } + properties: { + supportsHttpsTrafficOnly: true + allowBlobPublicAccess: false + minimumTlsVersion: 'TLS1_2' + networkAcls: { + bypass: 'AzureServices' + defaultAction: 'Deny' + ipRules: [] + virtualNetworkRules: [ + { + id: virtualNetwork::fnappSubnet.id + action: 'Allow' + } + ] + } + } + } + eventHub: { + sku: { + name: 'Standard' + } + properties: { + disableLocalAuth: useGraphEventHubManagedIdentity + // privateEndpointConnections: [{ privateEndpoint: { id: '' } }] + } + } + functionApp: { + identity: { + type: 'SystemAssigned' + } + properties: { + clientAffinityEnabled: false + httpsOnly: true + siteConfig: { + alwaysOn: false + netFrameworkVersion: 'v6.0' + ftpsState: 'Disabled' + } + virtualNetworkSubnetId: virtualNetwork::fnappSubnet.id + } + } + keyvault: { + properties: { + tenantId: subscription().tenantId + // This is set to Enabled because the function app needs to be able to access the key vault, it is restricted by the networkAcls + publicNetworkAccess: 'Enabled' + enableRbacAuthorization: true + sku: { + name: 'standard' + family: 'A' + } + networkAcls: { + bypass: 'AzureServices' + defaultAction: 'Deny' + virtualNetworkRules: [ { id: virtualNetwork::fnappSubnet.id } ] + ipRules: useGraphEventHubManagedIdentity ? [] : map(graphChangeNotificationSubnets[environment().name], s => { value: s }) + } + } + } + } + Custom: { + // document the requirements to create your own template + } +} + +// Virtual Network +resource virtualNetwork 'Microsoft.Network/virtualNetworks@2022-11-01' = if (startsWith(deploymentType, 'Restricted')) { + name: 'vnet-${resourceGroup().name}' + location: location + properties: { addressSpace: { addressPrefixes: [ '10.0.0.0/16' ] } } + resource fnappSubnet 'subnets' = { + name: 'fnapp-subnet' + properties: { + addressPrefix: '10.0.1.0/24' + serviceEndpoints: [ + { + service: 'Microsoft.KeyVault' + locations: [ location ] + } + { + service: 'Microsoft.Storage' + locations: [ location ] + } + { + service: 'Microsoft.Web' + locations: [ location ] + } + { + service: 'Microsoft.EventHub' + locations: [ location ] + } + ] + delegations: [ + { + name: 'fnapp-serverFarms' + properties: { + serviceName: 'Microsoft.Web/serverFarms' + } + } + ] + } + } +} + +// Storage Account +resource storageAccount 'Microsoft.Storage/storageAccounts@2022-09-01' = { + name: storageAccountName + location: location + kind: 'Storage' + sku: configurations[deploymentType].storage.sku + properties: configurations[deploymentType].storage.properties + resource queues 'queueServices' = { + name: 'default' + resource download 'queues' = { name: downloadQueueName } + } +} + +var graphChangeNotificationSubnets = loadJsonContent('GraphChangeNotificationSubnets.jsonc') + +// Event Hub +resource eventHubNamespace 'Microsoft.EventHub/namespaces@2022-10-01-preview' = { + name: baseResourceName + location: location + sku: configurations[deploymentType].eventHub.sku + properties: configurations[deploymentType].eventHub.properties + resource graphEventHub 'eventhubs' = { + name: 'graphevents' + properties: configurations[deploymentType].eventHub.eventhubs.properties + resource senderAuthorizationRule 'authorizationRules' = if (!useGraphEventHubManagedIdentity) { + name: 'sender' + properties: { rights: [ 'Send' ] } + } + } + resource networkAcl 'networkRuleSets' = if (startsWith(deploymentType, 'Restricted')) { + name: 'default' + properties: { + publicNetworkAccess: 'SecuredByPerimeter' + trustedServiceAccessEnabled: true + defaultAction: 'Deny' + virtualNetworkRules: [ { subnet: { id: virtualNetwork::fnappSubnet.id } } ] + ipRules: map(graphChangeNotificationSubnets[environment().name], s => { action: 'Allow', ipMask: s }) + } + } +} + +// Cosmos DB account +resource cosmosAccount 'Microsoft.DocumentDB/databaseAccounts@2023-09-15' existing = { + name: cosmosAccountName + resource database 'sqlDatabases' existing = { + name: callRecordsDatabaseName + resource container 'containers' existing = { + name: callRecordsContainerName + } + } +} + +// Function App +resource serverfarm 'Microsoft.Web/serverfarms@2022-09-01' = { + name: baseResourceName + location: location + sku: configurations[deploymentType].serverfarm.sku +} + +var GraphNotificationUrl = useGraphEventHubManagedIdentity /* +*/ ? 'EventHub:${eventHubNamespace.properties.serviceBusEndpoint}/eventhubname/${eventHubNamespace::graphEventHub.name}' /* +*/ : useSeparateKeyVaultForGraph /* +*/ ? 'EventHub:${graphKeyVault::graphEventHubConnectionString.properties.secretUri}' /* +*/ : 'EventHub:${keyvault::graphEventHubConnectionString.properties.secretUri}' + +resource functionApp 'Microsoft.Web/sites@2022-09-01' = { + name: '${baseResourceName}-function' + location: location + kind: 'functionapp' + identity: configurations[deploymentType].functionApp.identity + properties: configurations[deploymentType].functionApp.properties + resource appSettings 'config' = { + name: 'appsettings' + properties: toObject([ + { key: 'RenewSubscriptionScheduleCron', value: '0 0 */2 * * *' } + // CallRecords Queue Configuration + { key: 'CallRecordsQueueConnection__queueServiceUri', value: storageAccount.properties.primaryEndpoints.queue } + { key: 'CallRecordsQueueConnection__credential', value: 'managedidentity' } + { key: 'CallRecordsToDownloadQueueName', value: storageAccount::queues::download.name } + + // Graph Subscription Manager Configuration + { key: 'GraphSubscription__NotificationUrl', value: GraphNotificationUrl } + { key: 'GraphSubscription__Tenants', value: tenantDomain } + + { key: 'CallRecordInsightsDb__EndpointUri', value: cosmosAccount.properties.documentEndpoint } + { key: 'CallRecordInsightsDb__DatabaseName', value: cosmosAccount::database.properties.resource.id } + { key: 'CallRecordInsightsDb__ProcessedContainerName', value: cosmosAccount::database::container.properties.resource.id } + + { key: 'GraphNotificationEventHubName', value: eventHubNamespace::graphEventHub.name } + + { key: 'EventHubConnection__fullyQualifiedNamespace', value: split(split(eventHubNamespace.properties.serviceBusEndpoint,'://')[1],':')[0] } + { key: 'EventHubConnection__credential', value: 'managedidentity' } + + { key: 'AzureWebJobsStorage__accountName', value: storageAccount.name } + { key: 'AzureWebJobsSecretStorageType', value: 'keyvault' } + { key: 'AzureWebJobsSecretStorageKeyVaultUri', value: keyvault.properties.vaultUri } + { key: 'FUNCTIONS_EXTENSION_VERSION', value: '~4' } + { key: 'FUNCTIONS_WORKER_RUNTIME', value: 'dotnet' } + { key: 'WEBSITE_CONTENTAZUREFILECONNECTIONSTRING', value: '@Microsoft.KeyVault(VaultName=${keyvault.name};SecretName=${keyvault::storageAccountConnectionString.name})' } + { key: 'WEBSITE_CONTENTSHARE', value: toLower(functionApp.name) } + ], o => o.key, o => o.value) + } +} + +// Key Vault +resource keyvault 'Microsoft.KeyVault/vaults@2023-02-01' = { + name: keyvaultName + location: location + properties: configurations[deploymentType].keyvault.properties + resource storageAccountConnectionString 'secrets' = { + name: 'StorageAccountConnectionString' + properties: { + value: 'DefaultEndpointsProtocol=https;AccountName=${storageAccountName};EndpointSuffix=${environment().suffixes.storage};AccountKey=${storageAccount.listkeys().keys[0].value}' + attributes: { enabled: true } + contentType: 'text/plain' + } + } + + resource graphEventHubConnectionString 'secrets@2023-02-01' = if (!useGraphEventHubManagedIdentity && !useSeparateKeyVaultForGraph) { + name: 'GraphEventHubConnectionString' + properties: { + value: eventHubNamespace::graphEventHub::senderAuthorizationRule.listkeys().primaryConnectionString + attributes: { enabled: true } + contentType: 'text/plain' + } + } +} + +// If using a separate key vault for the graph, create it here +resource graphKeyVault 'Microsoft.KeyVault/vaults@2023-02-01' = if (!useGraphEventHubManagedIdentity && useSeparateKeyVaultForGraph) { + name: graphKeyVaultName + location: location + properties: configurations[deploymentType].keyvault.properties + + resource graphEventHubConnectionString 'secrets' = if (!useGraphEventHubManagedIdentity && useSeparateKeyVaultForGraph) { + name: 'GraphEventHubConnectionString' + properties: { + value: eventHubNamespace::graphEventHub::senderAuthorizationRule.listkeys().primaryConnectionString + attributes: { enabled: true } + contentType: 'text/plain' + } + } +} + +// Role Assignments +var roleDefinitionId = { + StorageAccount: { + // This is the built-in Storage Account Contributor role. See https://docs.microsoft.com/azure/role-based-access-control/built-in-roles#storage-account-contributor + Contributor: '17d1049b-9a84-46fb-8f53-869881c3d3ab' + Queue: { + Data: { + // This is the built-in Storage Queue Data Contributor role. See https://docs.microsoft.com/azure/role-based-access-control/built-in-roles#storage-queue-data-contributor + Contributor: '974c5e8b-45b9-4653-ba55-5f855dd0fb88' + } + } + Blob: { + Data: { + // This is the built-in Storage Blob Data Owner role. See https://docs.microsoft.com/azure/role-based-access-control/built-in-roles#storage-blob-data-owner + Owner: 'b7e6dc6d-f1e8-4753-8033-0f276bb0955b' + } + } + } + EventHubs: { + Data: { + // This is the built-in Azure Event Hubs Data Sender role. See https://docs.microsoft.com/azure/role-based-access-control/built-in-roles#event-hubs-data-sender + Sender: '2b629674-e913-4c01-ae53-ef4638d8f975' + // This is the built-in Azure Event Hubs Data Receiver role. See https://docs.microsoft.com/azure/role-based-access-control/built-in-roles#event-hubs-data-receiver + Receiver: 'a638d3c7-ab3a-418d-83e6-5f17a39d4fde' + } + } + KeyVault: { + Secrets: { + // This is the built-in Key Vault Secrets Officer role. See https://docs.microsoft.com/azure/role-based-access-control/built-in-roles#key-vault-secrets-officer + Officer: 'b86a8fe4-44ce-4948-aee5-eccb2c155cd7' + // This is the built-in Key Vault Secrets User role. See https://docs.microsoft.com/azure/role-based-access-control/built-in-roles#key-vault-secrets-user + User: '4633458b-17de-408a-b874-0445c86b69e6' + } + } + CosmosDB: { + Data: { + Contributor: '00000000-0000-0000-0000-000000000002' + } + } +} + +var neededRoles = { + functionApp: { + StorageAccount: [ + roleDefinitionId.StorageAccount.Contributor + roleDefinitionId.StorageAccount.Queue.Data.Contributor + roleDefinitionId.StorageAccount.Blob.Data.Owner + ] + EventHubs: [ + roleDefinitionId.EventHubs.Data.Receiver + ] + KeyVault: [ + roleDefinitionId.KeyVault.Secrets.Officer + ] + CosmosDB: [ + roleDefinitionId.CosmosDB.Data.Contributor + ] + } + graphChangeTrackingApp: { + EventHubs: (useGraphEventHubManagedIdentity) ? [ roleDefinitionId.EventHubs.Data.Sender ] : [] + KeyVault: (!useGraphEventHubManagedIdentity) ? [ roleDefinitionId.KeyVault.Secrets.User ] : [] + } +} + +resource functionAppStorageRoleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = [for role in neededRoles.functionApp.StorageAccount: { + scope: storageAccount + name: guid(functionApp.id, role, resourceGroup().id) + properties: { + roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', role) + principalId: functionApp.identity.principalId + principalType: 'ServicePrincipal' + } +}] + +resource functionAppEventHubsRoleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = [for role in neededRoles.functionApp.EventHubs: { + scope: eventHubNamespace::graphEventHub + name: guid(functionApp.id, role, resourceGroup().id) + properties: { + roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', role) + principalId: functionApp.identity.principalId + principalType: 'ServicePrincipal' + } +}] + +resource functionAppKeyVaultRoleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = [for role in neededRoles.functionApp.KeyVault: { + scope: keyvault + name: guid(functionApp.id, role, resourceGroup().id) + properties: { + roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', role) + principalId: functionApp.identity.principalId + principalType: 'ServicePrincipal' + } +}] + +resource functionAppCosmosDBRoleAssignment 'Microsoft.DocumentDB/databaseAccounts/sqlRoleAssignments@2023-09-15' = [for role in neededRoles.functionApp.CosmosDB: { + name: guid(functionApp.id, role, resourceGroup().id) + parent: cosmosAccount + properties: { + roleDefinitionId: resourceId('Microsoft.DocumentDB/databaseAccounts/sqlRoleDefinitions', cosmosAccountName, role) + principalId: functionApp.identity.principalId + scope: replace(cosmosAccount::database.id, '/sqlDatabases/', '/dbs/') + } +}] + +resource graphChangeTrackingAppRoleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = [for role in neededRoles.graphChangeTrackingApp.EventHubs: { + scope: eventHubNamespace::graphEventHub + name: guid(graphChangeTrackingAppObjectId, role, resourceGroup().id) + properties: { + roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', role) + principalId: graphChangeTrackingAppObjectId + principalType: 'ServicePrincipal' + } +}] + +resource graphChangeTrackingAppKeyVaultRoleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = [for role in neededRoles.graphChangeTrackingApp.KeyVault: { + scope: useSeparateKeyVaultForGraph ? graphKeyVault::graphEventHubConnectionString : keyvault::graphEventHubConnectionString + name: guid(graphChangeTrackingAppObjectId, role, resourceGroup().id) + properties: { + roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', role) + principalId: graphChangeTrackingAppObjectId + principalType: 'ServicePrincipal' + } +}] + +// Outputs +output keyVaultName string = keyvaultName +output appDomain string = functionApp.properties.defaultHostName +output functionName string = functionApp.name +output functionAppIdentity object = functionApp.identity +output functionAppSubnetId string = deploymentType == 'RestrictedProduction' ? functionApp.properties.virtualNetworkSubnetId : '' diff --git a/deploy/bicep/deployKusto.bicep b/deploy/bicep/deployKusto.bicep new file mode 100644 index 0000000..cad690c --- /dev/null +++ b/deploy/bicep/deployKusto.bicep @@ -0,0 +1,153 @@ +// Parameters +@description('The base name to use for the resources that will be provisioned.') +param clusterNamePrefix string = 'crinsights' + +@description('Location for all resources.') +param location string = resourceGroup().location + +@description('The type of deployment. Production is a standard deployment. DevTest is a smaller deployment with no SLA.') +@allowed([ + 'Production' + 'RestrictedProduction' + 'DevTest' +]) +param deploymentType string = 'Production' + +@description('The name of the Kusto database.') +param databaseName string = 'CallRecordInsights' + +@description('The name of the existing Kusto cluster to use.') +param existingKustoClusterName string = 'NOEXISTINGKUSTOCLUSTER' + +@description('The type of identity to assign to the cluster. SystemAssigned is the default. None will not assign an identity. UserAssigned will assign the identity specified in the identity parameter.') +param identity string = 'SystemAssigned' + +// T-Shirt sizing +var clusterConfigurations = { + DevTest: { + cluster: { + sku: { + name: 'Dev(No SLA)_Standard_E2a_v4' + tier: 'Basic' + capacity: 1 + } + properties: { + enableAutoStop: true + } + } + database: { + properties: { + softDeletePeriod: 'P180D' + hotCachePeriod: 'P7D' + } + } + } + Production: { + cluster: { + sku: { + name: 'Standard_E2ads_v5' + tier: 'Standard' + capacity: 2 + } + properties: {} + } + database: { + properties: { + softDeletePeriod: 'P365D' + hotCachePeriod: 'P31D' + } + } + } + // this will eventually be locked down netowrk wise, but for now, just using the same as production + RestrictedProduction: { + cluster: { + sku: { + name: 'Standard_E2ads_v5' + tier: 'Standard' + capacity: 2 + } + properties: {} + } + database: { + properties: { + softDeletePeriod: 'P365D' + hotCachePeriod: 'P31D' + } + } + } +} + +var clusterIdentity = identity == 'SystemAssigned' || identity == 'None'/* + */? { + type: identity + } /* + */: { + type: 'UserAssigned' + userAssignedIdentities: { + '${identity}': {} + } + } + + +// clean up the resource name +// I would prefer this to be in a function/module, but the current limitations of func and module do not allow for this easily +var input = clusterNamePrefix +var validChars = ['alpha','numeric'] +var validFirstChars = ['alpha','numeric'] // assumed to be subset of validChars +var validEndChars = ['alpha','numeric'] // assumed to be subset of validChars +var maxLength = 24 +var upper = ['A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z'] +var lower = ['a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'] +var charSets = { + upper: upper + lower: lower + alpha: concat(upper,lower) + numeric: ['0','1','2','3','4','5','6','7','8','9'] + hyphen: ['-'] + underscore: ['_'] + period: ['.'] +} +var validCharSet = flatten(map(validChars , s => charSets[s])) +var validFirstCharSet = flatten(map(validFirstChars , s => charSets[s])) +var validEndCharSet = flatten(map(validEndChars , s => charSets[s])) + +// get a unique string based on the given seed +var caseShifted = toLower('${input}${(uniqueString(resourceGroup().id))}') +var cleanedUnique = reduce(map(range(0, length(caseShifted)-1), i => substring(caseShifted,i,1)), '', (c,n) => '${c}${(c == '-' && n == '-' ? '' : n)}') +var indexedChars = items(toObject(range(0,length(cleanedUnique)),i => '${i}', i => substring(cleanedUnique,i,1))) +var firstIndexedChar = sort(filter(indexedChars, c => contains(validFirstCharSet, c.value)), (c,n) => int(c.key) < int(n.key))[0] +var endIndexedChar = sort(filter(indexedChars, c => int(c.key) > int(firstIndexedChar.key) && (maxLength > -1 && int(c.key) < (int(firstIndexedChar.key) + maxLength)) && contains(validEndCharSet, c.value)), (c,n) => int(c.key) > int(n.key))[0] +var validIndexedChars = sort(filter(indexedChars, c => int(c.key) > int(firstIndexedChar.key) && int(c.key) < int(endIndexedChar.key) && contains(validCharSet, c.value)), (c,n) => int(c.key) < int(n.key)) +var clusterResourceName = '${firstIndexedChar.value}${reduce(validIndexedChars, '', (c,n) => '${c}${n.value}')}${endIndexedChar.value}' + +var existing = !empty(trim(existingKustoClusterName)) && existingKustoClusterName != 'NOEXISTINGKUSTOCLUSTER' + +resource existingCluster 'Microsoft.Kusto/clusters@2023-08-15' existing = if (existing) { + name: existingKustoClusterName +} + +resource existingDatabase 'Microsoft.Kusto/clusters/databases@2023-08-15' = if (existing) { + name: '${existing ? existingKustoClusterName : 'bogus'}/${databaseName}' + location: location + properties: clusterConfigurations[deploymentType].database.properties + kind: 'ReadWrite' +} + +resource newCluster 'Microsoft.Kusto/clusters@2023-08-15' = if (!existing) { + name: clusterResourceName + location: location + sku: clusterConfigurations[deploymentType].cluster.sku + identity: clusterIdentity + properties: clusterConfigurations[deploymentType].cluster.properties + resource database 'databases' = { + name: databaseName + location: location + properties: clusterConfigurations[deploymentType].database.properties + kind: 'ReadWrite' + } +} + +// Outputs +output Name string = existing ? existingCluster.name : newCluster.name +output Uri string = existing ? existingCluster.properties.uri : newCluster.properties.uri +output DatabaseName string = existing ? existingDatabase.name : newCluster::database.name diff --git a/deploy/bicep/functions/assertRequiredRoles.bicep b/deploy/bicep/functions/assertRequiredRoles.bicep new file mode 100644 index 0000000..0dfa953 --- /dev/null +++ b/deploy/bicep/functions/assertRequiredRoles.bicep @@ -0,0 +1,43 @@ +param location string = resourceGroup().location + +param principalId string + +param roleIds array + +param graphEndpoint string = 'graph.microsoft.com' + +param forceUpdateTag string = newGuid() + +resource assertRequiredRoles 'Microsoft.Resources/deploymentScripts@2023-08-01' = { + name: 'assertRequiredRoles-${guid(principalId,'${roleIds}')}' + kind: 'AzureCLI' + location: location + properties: { + arguments: '${principalId} ${graphEndpoint} ${roleIds}' + scriptContent: ''' + PRINCIPAL_ID=$1; shift + GRAPH_ENDPOINT=$1; shift + NEEDED_ROLES=( "$@" ) + REQUEST_URL="https://$GRAPH_ENDPOINT/v1.0/servicePrincipals/$PRINCIPAL_ID/appRoleAssignments" + RESPONSES=() + + GRAPH_SPN=$(az ad sp list --spn '00000003-0000-0000-c000-000000000000' --query '[].id' --output tsv) + CURRENT_ASSIGNMENTS=$(az rest --method get --url $REQUEST_URL | jq -r ".value[] | select(.resourceId==\"$GRAPH_SPN\") | .appRoleId") + for role in "${NEEDED_ROLES[@]}"; do + if [[ ! " ${CURRENT_ASSIGNMENTS[@]} " =~ " $role " ]]; then + BODY="{\"principalId\":\"$PRINCIPAL_ID\",\"resourceId\":\"$GRAPH_SPN\",\"appRoleId\":\"$role\"}" + RESPONSE=$(az rest --method post --url $REQUEST_URL --body $BODY) + RESPONSES+=("$RESPONSE") + fi + done + + echo ${RESPONSES[@]} | jq -n '{responses:[inputs]}' > $AZ_SCRIPTS_OUTPUT_PATH + ''' + azCliVersion: '2.55.0' + retentionInterval: 'P1D' + cleanupPreference: 'OnSuccess' + forceUpdateTag: forceUpdateTag + } +} + +output assertRequiredRoles object = assertRequiredRoles.properties.outputs diff --git a/deploy/bicep/kustoScripts/Configure.kql b/deploy/bicep/kustoScripts/Configure.kql new file mode 100644 index 0000000..901ce49 --- /dev/null +++ b/deploy/bicep/kustoScripts/Configure.kql @@ -0,0 +1,303 @@ +.create-or-alter function with (docstring = "Audio Classifier",folder = "PTSScripts") AudioClassifier( + AverageJitter: timespan, AverageRoundTripTime: timespan, AveragePacketLossRate: real, PacketUtilization: long) { + (AveragePacketLossRate > 0.1 or (AverageRoundTripTime/1ms) > 500 or (AverageJitter/1ms) > 30) and PacketUtilization > 1000 +} + +.create-or-alter function with (docstring = "Video Classifier",folder = "PTSScripts") VideoClassifier( + AverageVideoFrameLossPercentage: real, AverageVideoFrameRate: real, PostForwardErrorCorrectionPacketLossRate: real) { + iif(isnotempty(AverageVideoFrameLossPercentage), + AverageVideoFrameLossPercentage > 50, + iif(isnotempty(AverageVideoFrameRate), + AverageVideoFrameRate < 7, + PostForwardErrorCorrectionPacketLossRate > 0.15 + ) + ) +} + +.create-or-alter function with (docstring = "VBSS Classifier",folder = "PTSScripts") VBSSClassifier( + AverageVideoFrameLossPercentage: real, AverageVideoFrameRate: real, PostForwardErrorCorrectionPacketLossRate: real) { + iif(isnotempty(AverageVideoFrameLossPercentage), + AverageVideoFrameLossPercentage > 50, + iif(isnotempty(AverageVideoFrameRate), + AverageVideoFrameRate < 2, + PostForwardErrorCorrectionPacketLossRate > 0.15 + ) + ) +} + +.create-or-alter function with (folder = "PTSScripts") ApplyClassifiers( + T:(MediaLabel: string, AverageJitter: timespan, AverageRoundTripTime: timespan, AveragePacketLossRate: real, PacketUtilization: long, + AverageVideoFrameLossPercentage: real, AverageVideoFrameRate: real, PostForwardErrorCorrectionPacketLossRate: real)) { + T | extend IsClassifiedPoorStream = case( + MediaLabel has_cs 'audio', AudioClassifier(AverageJitter, AverageRoundTripTime, AveragePacketLossRate, PacketUtilization), + MediaLabel has_cs 'applicationsharing', VBSSClassifier(AverageVideoFrameLossPercentage, AverageVideoFrameRate, PostForwardErrorCorrectionPacketLossRate), + MediaLabel has_cs 'video', VideoClassifier(AverageVideoFrameLossPercentage, AverageVideoFrameRate, PostForwardErrorCorrectionPacketLossRate), + bool(null) + ) +} + +.create-or-alter materialized-view with (autoUpdateSchema = true, lookback = 30d) ##VIEW_NAME## on table ##TABLE_NAME## { + table('##TABLE_NAME##') + | summarize take_any(*) by CallRecordTenantIdContext, CallId, SessionId, StreamId, StreamDirection, MediaLabel +} + +.create-or-alter function ##FUNCTION_NAME##(numDays: int = long(-1)) { + ApplyClassifiers(materialized_view('##VIEW_NAME##')) + | where numDays < 0 or CallEndTime >= ago(make_timespan(numDays,0,0,0) + ) +} + +.create-or-alter function with (docstring = "Get All Call Records for a given user in the last {days} days") GetUserCallRecords(userId: guid, numDays: int = long(-1)) { + ##FUNCTION_NAME##(numDays) + | where Caller_UserId == userId or Callee_UserId == userId +} + +.create-or-alter table ##TABLE_NAME## ingestion json mapping "CallRecordMappingJsonMapping" +``` +[ + {"column":"CallRecordTenantIdContext","datatype":"string","path":"$.CallRecordTenantIdContext"}, + {"column":"CallId","datatype":"guid","path":"$.CallId"}, + {"column":"SessionId","datatype":"guid","path":"$.SessionId"}, + {"column":"StreamId","datatype":"string","path":"$.StreamId"}, + {"column":"StreamDirection","datatype":"string","path":"$.StreamDirection"}, + {"column":"MediaLabel","datatype":"string","path":"$.MediaLabel"}, + {"column":"CallStartTime","datatype":"datetime","path":"$.CallStartTime"}, + {"column":"CallEndTime","datatype":"datetime","path":"$.CallEndTime"}, + {"column":"SessionStartTime","datatype":"datetime","path":"$.SessionStartTime"}, + {"column":"SessionEndTime","datatype":"datetime","path":"$.SessionEndTime"}, + {"column":"LastModifiedDateTimeOffset","datatype":"datetime","path":"$.LastModifiedDateTimeOffset"}, + {"column":"CallType","datatype":"string","path":"$.CallType"}, + {"column":"JoinWebUrl","datatype":"string","path":"$.JoinWebUrl"}, + {"column":"VideoCodec","datatype":"string","path":"$.VideoCodec"}, + {"column":"AudioCodec","datatype":"string","path":"$.AudioCodec"}, + {"column":"WasMediaBypassed","datatype":"bool","path":"$.WasMediaBypassed"}, + {"column":"FailureStage","datatype":"string","path":"$.FailureStage"}, + {"column":"FailureReason","datatype":"string","path":"$.FailureReason"}, + {"column":"PacketUtilization","datatype":"long","path":"$.PacketUtilization"}, + {"column":"AverageBandwidthEstimate","datatype":"long","path":"$.AverageBandwidthEstimate"}, + {"column":"AverageJitter","datatype":"timespan","path":"$.AverageJitter"}, + {"column":"MaxJitter","datatype":"timespan","path":"$.MaxJitter"}, + {"column":"AverageRoundTripTime","datatype":"timespan","path":"$.AverageRoundTripTime"}, + {"column":"MaxRoundTripTime","datatype":"timespan","path":"$.MaxRoundTripTime"}, + {"column":"AverageAudioNetworkJitter","datatype":"timespan","path":"$.AverageAudioNetworkJitter"}, + {"column":"MaxAudioNetworkJitter","datatype":"timespan","path":"$.MaxAudioNetworkJitter"}, + {"column":"AverageAudioDegradation","datatype":"real","path":"$.AverageAudioDegradation"}, + {"column":"AveragePacketLossRate","datatype":"real","path":"$.AveragePacketLossRate"}, + {"column":"MaxPacketLossRate","datatype":"real","path":"$.MaxPacketLossRate"}, + {"column":"PostForwardErrorCorrectionPacketLossRate","datatype":"real","path":"$.PostForwardErrorCorrectionPacketLossRate"}, + {"column":"AverageRatioOfConcealedSamples","datatype":"real","path":"$.AverageRatioOfConcealedSamples"}, + {"column":"MaxRatioOfConcealedSamples","datatype":"real","path":"$.MaxRatioOfConcealedSamples"}, + {"column":"LowVideoProcessingCapabilityRatio","datatype":"real","path":"$.LowVideoProcessingCapabilityRatio"}, + {"column":"AverageVideoFrameRate","datatype":"real","path":"$.AverageVideoFrameRate"}, + {"column":"AverageReceivedFrameRate","datatype":"real","path":"$.AverageReceivedFrameRate"}, + {"column":"LowFrameRateRatio","datatype":"real","path":"$.LowFrameRateRatio"}, + {"column":"AverageVideoPacketLossRate","datatype":"real","path":"$.AverageVideoPacketLossRate"}, + {"column":"AverageVideoFrameLossPercentage","datatype":"real","path":"$.AverageVideoFrameLossPercentage"}, + {"column":"Organizer_UserDisplayName","datatype":"string","path":"$.Organizer_UserDisplayName"}, + {"column":"Organizer_UserId","datatype":"guid","path":"$.Organizer_UserId"}, + {"column":"Organizer_UserTenantId","datatype":"guid","path":"$.Organizer_UserTenantId"}, + {"column":"Organizer_ApplicationInstanceDisplayName","datatype":"string","path":"$.Organizer_ApplicationInstanceDisplayName"}, + {"column":"Organizer_ApplicationInstanceId","datatype":"guid","path":"$.Organizer_ApplicationInstanceId"}, + {"column":"Organizer_ApplicationInstanceTenantId","datatype":"guid","path":"$.Organizer_ApplicationInstanceTenantId"}, + {"column":"Organizer_GuestDisplayName","datatype":"string","path":"$.Organizer_GuestDisplayName"}, + {"column":"Organizer_GuestId","datatype":"guid","path":"$.Organizer_GuestId"}, + {"column":"Organizer_GuestTenantId","datatype":"guid","path":"$.Organizer_GuestTenantId"}, + {"column":"Organizer_PhoneDisplayName","datatype":"string","path":"$.Organizer_PhoneDisplayName"}, + {"column":"Organizer_PhoneId","datatype":"string","path":"$.Organizer_PhoneId"}, + {"column":"Organizer_PhoneTenantId","datatype":"guid","path":"$.Organizer_PhoneTenantId"}, + {"column":"Organizer_OnPremisesDisplayName","datatype":"string","path":"$.Organizer_OnPremisesDisplayName"}, + {"column":"Organizer_OnPremisesId","datatype":"guid","path":"$.Organizer_OnPremisesId"}, + {"column":"Organizer_OnPremisesTenantId","datatype":"guid","path":"$.Organizer_OnPremisesTenantId"}, + {"column":"Organizer_EncryptedDisplayName","datatype":"string","path":"$.Organizer_EncryptedDisplayName"}, + {"column":"Organizer_EncryptedId","datatype":"guid","path":"$.Organizer_EncryptedId"}, + {"column":"Organizer_EncryptedTenantId","datatype":"guid","path":"$.Organizer_EncryptedTenantId"}, + {"column":"Organizer_AcsUserDisplayName","datatype":"string","path":"$.Organizer_AcsUserDisplayName"}, + {"column":"Organizer_AcsUserId","datatype":"guid","path":"$.Organizer_AcsUserId"}, + {"column":"Organizer_AcsUserTenantId","datatype":"guid","path":"$.Organizer_AcsUserTenantId"}, + {"column":"Organizer_SpoolUserDisplayName","datatype":"string","path":"$.Organizer_SpoolUserDisplayName"}, + {"column":"Organizer_SpoolUserId","datatype":"guid","path":"$.Organizer_SpoolUserId"}, + {"column":"Organizer_SpoolUserTenantId","datatype":"guid","path":"$.Organizer_SpoolUserTenantId"}, + {"column":"Organizer_AcsApplicationInstanceDisplayName","datatype":"string","path":"$.Organizer_AcsApplicationInstanceDisplayName"}, + {"column":"Organizer_AcsApplicationInstanceId","datatype":"guid","path":"$.Organizer_AcsApplicationInstanceId"}, + {"column":"Organizer_AcsApplicationInstanceTenantId","datatype":"guid","path":"$.Organizer_AcsApplicationInstanceTenantId"}, + {"column":"Organizer_SpoolApplicationInstanceDisplayName","datatype":"string","path":"$.Organizer_SpoolApplicationInstanceDisplayName"}, + {"column":"Organizer_SpoolApplicationInstanceId","datatype":"guid","path":"$.Organizer_SpoolApplicationInstanceId"}, + {"column":"Organizer_SpoolApplicationInstanceTenantId","datatype":"guid","path":"$.Organizer_SpoolApplicationInstanceTenantId"}, + {"column":"Callee_UserDisplayName","datatype":"string","path":"$.Callee_UserDisplayName"}, + {"column":"Callee_UserId","datatype":"guid","path":"$.Callee_UserId"}, + {"column":"Callee_UserTenantId","datatype":"guid","path":"$.Callee_UserTenantId"}, + {"column":"Callee_ApplicationInstanceDisplayName","datatype":"string","path":"$.Callee_ApplicationInstanceDisplayName"}, + {"column":"Callee_ApplicationInstanceId","datatype":"guid","path":"$.Callee_ApplicationInstanceId"}, + {"column":"Callee_ApplicationInstanceTenantId","datatype":"guid","path":"$.Callee_ApplicationInstanceTenantId"}, + {"column":"Callee_GuestDisplayName","datatype":"string","path":"$.Callee_GuestDisplayName"}, + {"column":"Callee_GuestId","datatype":"guid","path":"$.Callee_GuestId"}, + {"column":"Callee_GuestTenantId","datatype":"guid","path":"$.Callee_GuestTenantId"}, + {"column":"Callee_PhoneDisplayName","datatype":"string","path":"$.Callee_PhoneDisplayName"}, + {"column":"Callee_PhoneId","datatype":"string","path":"$.Callee_PhoneId"}, + {"column":"Callee_PhoneTenantId","datatype":"guid","path":"$.Callee_PhoneTenantId"}, + {"column":"Callee_OnPremisesDisplayName","datatype":"string","path":"$.Callee_OnPremisesDisplayName"}, + {"column":"Callee_OnPremisesId","datatype":"guid","path":"$.Callee_OnPremisesId"}, + {"column":"Callee_OnPremisesTenantId","datatype":"guid","path":"$.Callee_OnPremisesTenantId"}, + {"column":"Callee_EncryptedDisplayName","datatype":"string","path":"$.Callee_EncryptedDisplayName"}, + {"column":"Callee_EncryptedId","datatype":"guid","path":"$.Callee_EncryptedId"}, + {"column":"Callee_EncryptedTenantId","datatype":"guid","path":"$.Callee_EncryptedTenantId"}, + {"column":"Callee_AcsUserDisplayName","datatype":"string","path":"$.Callee_AcsUserDisplayName"}, + {"column":"Callee_AcsUserId","datatype":"guid","path":"$.Callee_AcsUserId"}, + {"column":"Callee_AcsUserTenantId","datatype":"guid","path":"$.Callee_AcsUserTenantId"}, + {"column":"Callee_SpoolUserDisplayName","datatype":"string","path":"$.Callee_SpoolUserDisplayName"}, + {"column":"Callee_SpoolUserId","datatype":"guid","path":"$.Callee_SpoolUserId"}, + {"column":"Callee_SpoolUserTenantId","datatype":"guid","path":"$.Callee_SpoolUserTenantId"}, + {"column":"Callee_AcsApplicationInstanceDisplayName","datatype":"string","path":"$.Callee_AcsApplicationInstanceDisplayName"}, + {"column":"Callee_AcsApplicationInstanceId","datatype":"guid","path":"$.Callee_AcsApplicationInstanceId"}, + {"column":"Callee_AcsApplicationInstanceTenantId","datatype":"guid","path":"$.Callee_AcsApplicationInstanceTenantId"}, + {"column":"Callee_SpoolApplicationInstanceDisplayName","datatype":"string","path":"$.Callee_SpoolApplicationInstanceDisplayName"}, + {"column":"Callee_SpoolApplicationInstanceId","datatype":"guid","path":"$.Callee_SpoolApplicationInstanceId"}, + {"column":"Callee_SpoolApplicationInstanceTenantId","datatype":"guid","path":"$.Callee_SpoolApplicationInstanceTenantId"}, + {"column":"Callee_EndpointType","datatype":"string","path":"$.Callee_EndpointType"}, + {"column":"Callee_ProductFamily","datatype":"string","path":"$.Callee_ProductFamily"}, + {"column":"Callee_Platform","datatype":"string","path":"$.Callee_Platform"}, + {"column":"Callee_UserAgentHeaderValue","datatype":"string","path":"$.Callee_UserAgentHeaderValue"}, + {"column":"Callee_ServiceRole","datatype":"string","path":"$.Callee_ServiceRole"}, + {"column":"Callee_ApplicationVersion","datatype":"string","path":"$.Callee_ApplicationVersion"}, + {"column":"Callee_AzureAdAppId","datatype":"guid","path":"$.Callee_AzureAdAppId"}, + {"column":"Callee_CommunicationServiceId","datatype":"guid","path":"$.Callee_CommunicationServiceId"}, + {"column":"Callee_ConnectionType","datatype":"string","path":"$.Callee_ConnectionType"}, + {"column":"Callee_ReflexiveIPAddress","datatype":"string","path":"$.Callee_ReflexiveIPAddress"}, + {"column":"Callee_Subnet","datatype":"string","path":"$.Callee_Subnet"}, + {"column":"Callee_IpAddress","datatype":"string","path":"$.Callee_IpAddress"}, + {"column":"Callee_MacAddress","datatype":"string","path":"$.Callee_MacAddress"}, + {"column":"Callee_LinkSpeed","datatype":"long","path":"$.Callee_LinkSpeed"}, + {"column":"Callee_NetworkTransportProtocol","datatype":"string","path":"$.Callee_NetworkTransportProtocol"}, + {"column":"Callee_Port","datatype":"int","path":"$.Callee_Port"}, + {"column":"Callee_RelayIPAddress","datatype":"string","path":"$.Callee_RelayIPAddress"}, + {"column":"Callee_RelayPort","datatype":"int","path":"$.Callee_RelayPort"}, + {"column":"Callee_DnsSuffix","datatype":"string","path":"$.Callee_DnsSuffix"}, + {"column":"Callee_TraceRouteHops","datatype":"string","path":"$.Callee_TraceRouteHops"}, + {"column":"Callee_BSSID","datatype":"string","path":"$.Callee_BSSID"}, + {"column":"Callee_WifiRadioType","datatype":"string","path":"$.Callee_WifiRadioType"}, + {"column":"Callee_WifiBand","datatype":"string","path":"$.Callee_WifiBand"}, + {"column":"Callee_WifiChannel","datatype":"int","path":"$.Callee_WifiChannel"}, + {"column":"Callee_WifiSignalStrength","datatype":"int","path":"$.Callee_WifiSignalStrength"}, + {"column":"Callee_WifiBatteryCharge","datatype":"int","path":"$.Callee_WifiBatteryCharge"}, + {"column":"Callee_WifiMicrosoftDriver","datatype":"string","path":"$.Callee_WifiMicrosoftDriver"}, + {"column":"Callee_WifiMicrosoftDriverVersion","datatype":"string","path":"$.Callee_WifiMicrosoftDriverVersion"}, + {"column":"Callee_WifiVendorDriver","datatype":"string","path":"$.Callee_WifiVendorDriver"}, + {"column":"Callee_WifiVendorDriverVersion","datatype":"string","path":"$.Callee_WifiVendorDriverVersion"}, + {"column":"Callee_CaptureDeviceName","datatype":"string","path":"$.Callee_CaptureDeviceName"}, + {"column":"Callee_CaptureDeviceDriver","datatype":"string","path":"$.Callee_CaptureDeviceDriver"}, + {"column":"Callee_RenderDeviceName","datatype":"string","path":"$.Callee_RenderDeviceName"}, + {"column":"Callee_RenderDeviceDriver","datatype":"string","path":"$.Callee_RenderDeviceDriver"}, + {"column":"Callee_SentSignalLevel","datatype":"real","path":"$.Callee_SentSignalLevel"}, + {"column":"Callee_SentNoiseLevel","datatype":"real","path":"$.Callee_SentNoiseLevel"}, + {"column":"Callee_MicGlitchRate","datatype":"real","path":"$.Callee_MicGlitchRate"}, + {"column":"Callee_ReceivedSignalLevel","datatype":"real","path":"$.Callee_ReceivedSignalLevel"}, + {"column":"Callee_ReceivedNoiseLevel","datatype":"real","path":"$.Callee_ReceivedNoiseLevel"}, + {"column":"Callee_SpeakerGlitchRate","datatype":"real","path":"$.Callee_SpeakerGlitchRate"}, + {"column":"Callee_HowlingEventCount","datatype":"int","path":"$.Callee_HowlingEventCount"}, + {"column":"Callee_InitialSignalLevelRootMeanSquare","datatype":"real","path":"$.Callee_InitialSignalLevelRootMeanSquare"}, + {"column":"Callee_DeviceGlitchEventRatio","datatype":"real","path":"$.Callee_DeviceGlitchEventRatio"}, + {"column":"Callee_DeviceClippingEventRatio","datatype":"real","path":"$.Callee_DeviceClippingEventRatio"}, + {"column":"Callee_LowSpeechToNoiseEventRatio","datatype":"real","path":"$.Callee_LowSpeechToNoiseEventRatio"}, + {"column":"Callee_CaptureNotFunctioningEventRatio","datatype":"real","path":"$.Callee_CaptureNotFunctioningEventRatio"}, + {"column":"Callee_SentQualityEventRatio","datatype":"real","path":"$.Callee_SentQualityEventRatio"}, + {"column":"Callee_LowSpeechLevelEventRatio","datatype":"real","path":"$.Callee_LowSpeechLevelEventRatio"}, + {"column":"Callee_RenderNotFunctioningEventRatio","datatype":"real","path":"$.Callee_RenderNotFunctioningEventRatio"}, + {"column":"Callee_ReceivedQualityEventRatio","datatype":"real","path":"$.Callee_ReceivedQualityEventRatio"}, + {"column":"Callee_RenderZeroVolumeEventRatio","datatype":"real","path":"$.Callee_RenderZeroVolumeEventRatio"}, + {"column":"Callee_RenderMuteEventRatio","datatype":"real","path":"$.Callee_RenderMuteEventRatio"}, + {"column":"Callee_CpuInsufficentEventRatio","datatype":"real","path":"$.Callee_CpuInsufficentEventRatio"}, + {"column":"Callee_DelayEventRatio","datatype":"real","path":"$.Callee_DelayEventRatio"}, + {"column":"Callee_BandwidthLowEventRatio","datatype":"real","path":"$.Callee_BandwidthLowEventRatio"}, + {"column":"Callee_FeedbackRating","datatype":"string","path":"$.Callee_FeedbackRating"}, + {"column":"Callee_FeedbackText","datatype":"string","path":"$.Callee_FeedbackText"}, + {"column":"Callee_FeedbackTokens","datatype":"string","path":"$.Callee_FeedbackTokens"}, + {"column":"Caller_UserDisplayName","datatype":"string","path":"$.Caller_UserDisplayName"}, + {"column":"Caller_UserId","datatype":"guid","path":"$.Caller_UserId"}, + {"column":"Caller_UserTenantId","datatype":"guid","path":"$.Caller_UserTenantId"}, + {"column":"Caller_ApplicationInstanceDisplayName","datatype":"string","path":"$.Caller_ApplicationInstanceDisplayName"}, + {"column":"Caller_ApplicationInstanceId","datatype":"guid","path":"$.Caller_ApplicationInstanceId"}, + {"column":"Caller_ApplicationInstanceTenantId","datatype":"guid","path":"$.Caller_ApplicationInstanceTenantId"}, + {"column":"Caller_GuestDisplayName","datatype":"string","path":"$.Caller_GuestDisplayName"}, + {"column":"Caller_GuestId","datatype":"guid","path":"$.Caller_GuestId"}, + {"column":"Caller_GuestTenantId","datatype":"guid","path":"$.Caller_GuestTenantId"}, + {"column":"Caller_PhoneDisplayName","datatype":"string","path":"$.Caller_PhoneDisplayName"}, + {"column":"Caller_PhoneId","datatype":"string","path":"$.Caller_PhoneId"}, + {"column":"Caller_PhoneTenantId","datatype":"guid","path":"$.Caller_PhoneTenantId"}, + {"column":"Caller_OnPremisesDisplayName","datatype":"string","path":"$.Caller_OnPremisesDisplayName"}, + {"column":"Caller_OnPremisesId","datatype":"guid","path":"$.Caller_OnPremisesId"}, + {"column":"Caller_OnPremisesTenantId","datatype":"guid","path":"$.Caller_OnPremisesTenantId"}, + {"column":"Caller_EncryptedDisplayName","datatype":"string","path":"$.Caller_EncryptedDisplayName"}, + {"column":"Caller_EncryptedId","datatype":"guid","path":"$.Caller_EncryptedId"}, + {"column":"Caller_EncryptedTenantId","datatype":"guid","path":"$.Caller_EncryptedTenantId"}, + {"column":"Caller_AcsUserDisplayName","datatype":"string","path":"$.Caller_AcsUserDisplayName"}, + {"column":"Caller_AcsUserId","datatype":"guid","path":"$.Caller_AcsUserId"}, + {"column":"Caller_AcsUserTenantId","datatype":"guid","path":"$.Caller_AcsUserTenantId"}, + {"column":"Caller_SpoolUserDisplayName","datatype":"string","path":"$.Caller_SpoolUserDisplayName"}, + {"column":"Caller_SpoolUserId","datatype":"guid","path":"$.Caller_SpoolUserId"}, + {"column":"Caller_SpoolUserTenantId","datatype":"guid","path":"$.Caller_SpoolUserTenantId"}, + {"column":"Caller_AcsApplicationInstanceDisplayName","datatype":"string","path":"$.Caller_AcsApplicationInstanceDisplayName"}, + {"column":"Caller_AcsApplicationInstanceId","datatype":"guid","path":"$.Caller_AcsApplicationInstanceId"}, + {"column":"Caller_AcsApplicationInstanceTenantId","datatype":"guid","path":"$.Caller_AcsApplicationInstanceTenantId"}, + {"column":"Caller_SpoolApplicationInstanceDisplayName","datatype":"string","path":"$.Caller_SpoolApplicationInstanceDisplayName"}, + {"column":"Caller_SpoolApplicationInstanceId","datatype":"guid","path":"$.Caller_SpoolApplicationInstanceId"}, + {"column":"Caller_SpoolApplicationInstanceTenantId","datatype":"guid","path":"$.Caller_SpoolApplicationInstanceTenantId"}, + {"column":"Caller_EndpointType","datatype":"string","path":"$.Caller_EndpointType"}, + {"column":"Caller_ProductFamily","datatype":"string","path":"$.Caller_ProductFamily"}, + {"column":"Caller_Platform","datatype":"string","path":"$.Caller_Platform"}, + {"column":"Caller_UserAgentHeaderValue","datatype":"string","path":"$.Caller_UserAgentHeaderValue"}, + {"column":"Caller_ServiceRole","datatype":"string","path":"$.Caller_ServiceRole"}, + {"column":"Caller_ApplicationVersion","datatype":"string","path":"$.Caller_ApplicationVersion"}, + {"column":"Caller_AzureAdAppId","datatype":"guid","path":"$.Caller_AzureAdAppId"}, + {"column":"Caller_CommunicationServiceId","datatype":"guid","path":"$.Caller_CommunicationServiceId"}, + {"column":"Caller_ConnectionType","datatype":"string","path":"$.Caller_ConnectionType"}, + {"column":"Caller_ReflexiveIPAddress","datatype":"string","path":"$.Caller_ReflexiveIPAddress"}, + {"column":"Caller_Subnet","datatype":"string","path":"$.Caller_Subnet"}, + {"column":"Caller_IpAddress","datatype":"string","path":"$.Caller_IpAddress"}, + {"column":"Caller_MacAddress","datatype":"string","path":"$.Caller_MacAddress"}, + {"column":"Caller_LinkSpeed","datatype":"long","path":"$.Caller_LinkSpeed"}, + {"column":"Caller_NetworkTransportProtocol","datatype":"string","path":"$.Caller_NetworkTransportProtocol"}, + {"column":"Caller_Port","datatype":"int","path":"$.Caller_Port"}, + {"column":"Caller_RelayIPAddress","datatype":"string","path":"$.Caller_RelayIPAddress"}, + {"column":"Caller_RelayPort","datatype":"int","path":"$.Caller_RelayPort"}, + {"column":"Caller_DnsSuffix","datatype":"string","path":"$.Caller_DnsSuffix"}, + {"column":"Caller_TraceRouteHops","datatype":"string","path":"$.Caller_TraceRouteHops"}, + {"column":"Caller_BSSID","datatype":"string","path":"$.Caller_BSSID"}, + {"column":"Caller_WifiRadioType","datatype":"string","path":"$.Caller_WifiRadioType"}, + {"column":"Caller_WifiBand","datatype":"string","path":"$.Caller_WifiBand"}, + {"column":"Caller_WifiChannel","datatype":"int","path":"$.Caller_WifiChannel"}, + {"column":"Caller_WifiSignalStrength","datatype":"int","path":"$.Caller_WifiSignalStrength"}, + {"column":"Caller_WifiBatteryCharge","datatype":"int","path":"$.Caller_WifiBatteryCharge"}, + {"column":"Caller_WifiMicrosoftDriver","datatype":"string","path":"$.Caller_WifiMicrosoftDriver"}, + {"column":"Caller_WifiMicrosoftDriverVersion","datatype":"string","path":"$.Caller_WifiMicrosoftDriverVersion"}, + {"column":"Caller_WifiVendorDriver","datatype":"string","path":"$.Caller_WifiVendorDriver"}, + {"column":"Caller_WifiVendorDriverVersion","datatype":"string","path":"$.Caller_WifiVendorDriverVersion"}, + {"column":"Caller_CaptureDeviceName","datatype":"string","path":"$.Caller_CaptureDeviceName"}, + {"column":"Caller_CaptureDeviceDriver","datatype":"string","path":"$.Caller_CaptureDeviceDriver"}, + {"column":"Caller_RenderDeviceName","datatype":"string","path":"$.Caller_RenderDeviceName"}, + {"column":"Caller_RenderDeviceDriver","datatype":"string","path":"$.Caller_RenderDeviceDriver"}, + {"column":"Caller_SentSignalLevel","datatype":"real","path":"$.Caller_SentSignalLevel"}, + {"column":"Caller_SentNoiseLevel","datatype":"real","path":"$.Caller_SentNoiseLevel"}, + {"column":"Caller_MicGlitchRate","datatype":"real","path":"$.Caller_MicGlitchRate"}, + {"column":"Caller_ReceivedSignalLevel","datatype":"real","path":"$.Caller_ReceivedSignalLevel"}, + {"column":"Caller_ReceivedNoiseLevel","datatype":"real","path":"$.Caller_ReceivedNoiseLevel"}, + {"column":"Caller_SpeakerGlitchRate","datatype":"real","path":"$.Caller_SpeakerGlitchRate"}, + {"column":"Caller_HowlingEventCount","datatype":"int","path":"$.Caller_HowlingEventCount"}, + {"column":"Caller_InitialSignalLevelRootMeanSquare","datatype":"real","path":"$.Caller_InitialSignalLevelRootMeanSquare"}, + {"column":"Caller_DeviceGlitchEventRatio","datatype":"real","path":"$.Caller_DeviceGlitchEventRatio"}, + {"column":"Caller_DeviceClippingEventRatio","datatype":"real","path":"$.Caller_DeviceClippingEventRatio"}, + {"column":"Caller_LowSpeechToNoiseEventRatio","datatype":"real","path":"$.Caller_LowSpeechToNoiseEventRatio"}, + {"column":"Caller_CaptureNotFunctioningEventRatio","datatype":"real","path":"$.Caller_CaptureNotFunctioningEventRatio"}, + {"column":"Caller_SentQualityEventRatio","datatype":"real","path":"$.Caller_SentQualityEventRatio"}, + {"column":"Caller_LowSpeechLevelEventRatio","datatype":"real","path":"$.Caller_LowSpeechLevelEventRatio"}, + {"column":"Caller_RenderNotFunctioningEventRatio","datatype":"real","path":"$.Caller_RenderNotFunctioningEventRatio"}, + {"column":"Caller_ReceivedQualityEventRatio","datatype":"real","path":"$.Caller_ReceivedQualityEventRatio"}, + {"column":"Caller_RenderZeroVolumeEventRatio","datatype":"real","path":"$.Caller_RenderZeroVolumeEventRatio"}, + {"column":"Caller_RenderMuteEventRatio","datatype":"real","path":"$.Caller_RenderMuteEventRatio"}, + {"column":"Caller_CpuInsufficentEventRatio","datatype":"real","path":"$.Caller_CpuInsufficentEventRatio"}, + {"column":"Caller_DelayEventRatio","datatype":"real","path":"$.Caller_DelayEventRatio"}, + {"column":"Caller_BandwidthLowEventRatio","datatype":"real","path":"$.Caller_BandwidthLowEventRatio"}, + {"column":"Caller_FeedbackRating","datatype":"string","path":"$.Caller_FeedbackRating"}, + {"column":"Caller_FeedbackText","datatype":"string","path":"$.Caller_FeedbackText"}, + {"column":"Caller_FeedbackTokens","datatype":"string","path":"$.Caller_FeedbackTokens"} +] +``` \ No newline at end of file diff --git a/deploy/bicep/kustoScripts/CreateTable.kql b/deploy/bicep/kustoScripts/CreateTable.kql new file mode 100644 index 0000000..d88950a --- /dev/null +++ b/deploy/bicep/kustoScripts/CreateTable.kql @@ -0,0 +1,93 @@ +.create table ##TABLE_NAME## ( + CallRecordTenantIdContext: string, + CallId: guid, SessionId: guid, StreamId: string, StreamDirection: string, MediaLabel: string, + CallStartTime: datetime, CallEndTime: datetime, SessionStartTime: datetime, SessionEndTime: datetime, + LastModifiedDateTimeOffset: datetime, CallType: string, JoinWebUrl: string, VideoCodec: string, + AudioCodec: string, WasMediaBypassed: bool, FailureStage: string, FailureReason: string, + PacketUtilization: long, AverageBandwidthEstimate: long, AverageJitter: timespan, MaxJitter: timespan, + AverageRoundTripTime: timespan, MaxRoundTripTime: timespan, AverageAudioNetworkJitter: timespan, + MaxAudioNetworkJitter: timespan, AverageAudioDegradation: real, AveragePacketLossRate: real, + MaxPacketLossRate: real, PostForwardErrorCorrectionPacketLossRate: real, + AverageRatioOfConcealedSamples: real, MaxRatioOfConcealedSamples: real, + LowVideoProcessingCapabilityRatio: real, AverageVideoFrameRate: real, AverageReceivedFrameRate: real, + LowFrameRateRatio: real, AverageVideoPacketLossRate: real, AverageVideoFrameLossPercentage: real, + Organizer_UserDisplayName: string, Organizer_UserId: guid, Organizer_UserTenantId: guid, + Organizer_ApplicationInstanceDisplayName: string, Organizer_ApplicationInstanceId: guid, + Organizer_ApplicationInstanceTenantId: guid, Organizer_GuestDisplayName: string, + Organizer_GuestId: guid, Organizer_GuestTenantId: guid, Organizer_PhoneDisplayName: string, + Organizer_PhoneId: string, Organizer_PhoneTenantId: guid, Organizer_OnPremisesDisplayName: string, + Organizer_OnPremisesId: guid, Organizer_OnPremisesTenantId: guid, + Organizer_EncryptedDisplayName: string, Organizer_EncryptedId: guid, + Organizer_EncryptedTenantId: guid, Organizer_AcsUserDisplayName: string, Organizer_AcsUserId: guid, + Organizer_AcsUserTenantId: guid, Organizer_SpoolUserDisplayName: string, Organizer_SpoolUserId: guid, + Organizer_SpoolUserTenantId: guid, Organizer_AcsApplicationInstanceDisplayName: string, + Organizer_AcsApplicationInstanceId: guid, Organizer_AcsApplicationInstanceTenantId: guid, + Organizer_SpoolApplicationInstanceDisplayName: string, Organizer_SpoolApplicationInstanceId: guid, + Organizer_SpoolApplicationInstanceTenantId: guid, Callee_UserDisplayName: string, Callee_UserId: guid, + Callee_UserTenantId: guid, Callee_ApplicationInstanceDisplayName: string, + Callee_ApplicationInstanceId: guid, Callee_ApplicationInstanceTenantId: guid, + Callee_GuestDisplayName: string, Callee_GuestId: guid, Callee_GuestTenantId: guid, + Callee_PhoneDisplayName: string, Callee_PhoneId: string, Callee_PhoneTenantId: guid, + Callee_OnPremisesDisplayName: string, Callee_OnPremisesId: guid, Callee_OnPremisesTenantId: guid, + Callee_EncryptedDisplayName: string, Callee_EncryptedId: guid, Callee_EncryptedTenantId: guid, + Callee_AcsUserDisplayName: string, Callee_AcsUserId: guid, Callee_AcsUserTenantId: guid, + Callee_SpoolUserDisplayName: string, Callee_SpoolUserId: guid, Callee_SpoolUserTenantId: guid, + Callee_AcsApplicationInstanceDisplayName: string, Callee_AcsApplicationInstanceId: guid, + Callee_AcsApplicationInstanceTenantId: guid, Callee_SpoolApplicationInstanceDisplayName: string, + Callee_SpoolApplicationInstanceId: guid, Callee_SpoolApplicationInstanceTenantId: guid, + Callee_EndpointType: string, Callee_ProductFamily: string, Callee_Platform: string, + Callee_UserAgentHeaderValue: string, Callee_ServiceRole: string, Callee_ApplicationVersion: string, + Callee_AzureAdAppId: guid, Callee_CommunicationServiceId: guid, Callee_ConnectionType: string, + Callee_ReflexiveIPAddress: string, Callee_Subnet: string, Callee_IpAddress: string, + Callee_MacAddress: string, Callee_LinkSpeed: long, Callee_NetworkTransportProtocol: string, + Callee_Port: int, Callee_RelayIPAddress: string, Callee_RelayPort: int, Callee_DnsSuffix: string, + Callee_TraceRouteHops: string, Callee_BSSID: string, Callee_WifiRadioType: string, + Callee_WifiBand: string, Callee_WifiChannel: int, Callee_WifiSignalStrength: int, + Callee_WifiBatteryCharge: int, Callee_WifiMicrosoftDriver: string, + Callee_WifiMicrosoftDriverVersion: string, Callee_WifiVendorDriver: string, + Callee_WifiVendorDriverVersion: string, Callee_CaptureDeviceName: string, + Callee_CaptureDeviceDriver: string, Callee_RenderDeviceName: string, Callee_RenderDeviceDriver: string, + Callee_SentSignalLevel: real, Callee_SentNoiseLevel: real, Callee_MicGlitchRate: real, + Callee_ReceivedSignalLevel: real, Callee_ReceivedNoiseLevel: real, Callee_SpeakerGlitchRate: real, + Callee_HowlingEventCount: int, Callee_InitialSignalLevelRootMeanSquare: real, + Callee_DeviceGlitchEventRatio: real, Callee_DeviceClippingEventRatio: real, + Callee_LowSpeechToNoiseEventRatio: real, Callee_CaptureNotFunctioningEventRatio: real, + Callee_SentQualityEventRatio: real, Callee_LowSpeechLevelEventRatio: real, + Callee_RenderNotFunctioningEventRatio: real, Callee_ReceivedQualityEventRatio: real, + Callee_RenderZeroVolumeEventRatio: real, Callee_RenderMuteEventRatio: real, + Callee_CpuInsufficentEventRatio: real, Callee_DelayEventRatio: real, Callee_BandwidthLowEventRatio: real, + Callee_FeedbackRating: string, Callee_FeedbackText: string, Callee_FeedbackTokens: string, + Caller_UserDisplayName: string, Caller_UserId: guid, Caller_UserTenantId: guid, + Caller_ApplicationInstanceDisplayName: string, Caller_ApplicationInstanceId: guid, + Caller_ApplicationInstanceTenantId: guid, Caller_GuestDisplayName: string, Caller_GuestId: guid, + Caller_GuestTenantId: guid, Caller_PhoneDisplayName: string, Caller_PhoneId: string, + Caller_PhoneTenantId: guid, Caller_OnPremisesDisplayName: string, Caller_OnPremisesId: guid, + Caller_OnPremisesTenantId: guid, Caller_EncryptedDisplayName: string, Caller_EncryptedId: guid, + Caller_EncryptedTenantId: guid, Caller_AcsUserDisplayName: string, Caller_AcsUserId: guid, + Caller_AcsUserTenantId: guid, Caller_SpoolUserDisplayName: string, Caller_SpoolUserId: guid, + Caller_SpoolUserTenantId: guid, Caller_AcsApplicationInstanceDisplayName: string, + Caller_AcsApplicationInstanceId: guid, Caller_AcsApplicationInstanceTenantId: guid, + Caller_SpoolApplicationInstanceDisplayName: string, Caller_SpoolApplicationInstanceId: guid, + Caller_SpoolApplicationInstanceTenantId: guid, Caller_EndpointType: string, Caller_ProductFamily: string, + Caller_Platform: string, Caller_UserAgentHeaderValue: string, Caller_ServiceRole: string, + Caller_ApplicationVersion: string, Caller_AzureAdAppId: guid, Caller_CommunicationServiceId: guid, + Caller_ConnectionType: string, Caller_ReflexiveIPAddress: string, Caller_Subnet: string, + Caller_IpAddress: string, Caller_MacAddress: string, Caller_LinkSpeed: long, + Caller_NetworkTransportProtocol: string, Caller_Port: int, Caller_RelayIPAddress: string, + Caller_RelayPort: int, Caller_DnsSuffix: string, Caller_TraceRouteHops: string, Caller_BSSID: string, + Caller_WifiRadioType: string, Caller_WifiBand: string, Caller_WifiChannel: int, + Caller_WifiSignalStrength: int, Caller_WifiBatteryCharge: int, Caller_WifiMicrosoftDriver: string, + Caller_WifiMicrosoftDriverVersion: string, Caller_WifiVendorDriver: string, + Caller_WifiVendorDriverVersion: string, Caller_CaptureDeviceName: string, + Caller_CaptureDeviceDriver: string, Caller_RenderDeviceName: string, Caller_RenderDeviceDriver: string, + Caller_SentSignalLevel: real, Caller_SentNoiseLevel: real, Caller_MicGlitchRate: real, + Caller_ReceivedSignalLevel: real, Caller_ReceivedNoiseLevel: real, Caller_SpeakerGlitchRate: real, + Caller_HowlingEventCount: int, Caller_InitialSignalLevelRootMeanSquare: real, + Caller_DeviceGlitchEventRatio: real, Caller_DeviceClippingEventRatio: real, + Caller_LowSpeechToNoiseEventRatio: real, Caller_CaptureNotFunctioningEventRatio: real, + Caller_SentQualityEventRatio: real, Caller_LowSpeechLevelEventRatio: real, + Caller_RenderNotFunctioningEventRatio: real, Caller_ReceivedQualityEventRatio: real, + Caller_RenderZeroVolumeEventRatio: real, Caller_RenderMuteEventRatio: real, + Caller_CpuInsufficentEventRatio: real, Caller_DelayEventRatio: real, Caller_BandwidthLowEventRatio: real, + Caller_FeedbackRating: string, Caller_FeedbackText: string, Caller_FeedbackTokens: string +) \ No newline at end of file diff --git a/deploy/deploy.ps1 b/deploy/deploy.ps1 new file mode 100644 index 0000000..68b337a --- /dev/null +++ b/deploy/deploy.ps1 @@ -0,0 +1,544 @@ +using namespace System.Text +using namespace System.Collections +using namespace System.Collections.Generic +using namespace System.Management.Automation +using namespace System.Runtime.InteropServices + +[CmdletBinding()] +param( + [Parameter(Mandatory)] + [string] + $ResourceGroupName, + + [Parameter()] + [ValidatePattern('^[a-z][a-z\d-]{1,20}[a-z\d]$')] + [string] + $BaseResourceName = $ResourceGroupName, + + [Parameter(Mandatory)] + [string] + $SubscriptionId, + + [ValidateSet('DevTest','Production','RestrictedProduction')] + $DeploymentSize = 'Production', + + [Parameter(HelpMessage = 'The Azure region that''s right for you. Not every resource is available in every region.')] + [ValidateSet('australiacentral', 'australiaeast', 'australiasoutheast', 'brazilsouth', 'canadacentral', 'canadaeast', 'centralindia', 'centralus', 'eastasia', + 'eastus', 'eastus2', 'francecentral', 'germanywestcentral', 'japaneast', 'japanwest', 'koreacentral', 'koreasouth', 'northcentralus', 'northeurope', 'norwayeast', + 'polandcentral', 'qatarcentral', 'southafricanorth', 'southcentralus', 'southeastasia', 'southindia', 'swedencentral', 'switzerlandnorth', 'uaenorth', 'uksouth', + 'ukwest', 'westcentralus', 'westeurope', 'westindia', 'westus', 'westus2', 'westus3')] + [string] + $Location = 'westus', + + [Parameter(HelpMessage = 'The URL to the git repository to deploy.')] + [AllowEmptyString()] + [string] + $GitRepoUrl = 'https://github.com/OfficeDev/microsoft-teams-apps-callrecord-insights.git', + + [Parameter(HelpMessage = 'The branch of the git repository to deploy.')] + [AllowEmptyString()] + [string] + $GitBranch = 'main', + + [Parameter(HelpMessage = 'The domain of the tenant that will be monitored for Call Records.')] + [string] + $TenantDomain, + + [Parameter(HelpMessage = 'The name of the cosmos account to use.')] + [string] + $CosmosAccountName = "${BaseResourceName}cdb", + + [Parameter(HelpMessage = 'The name of the database to store call records in the cosmos account.')] + [string] + $CosmosCallRecordsDatabaseName = 'callrecordinsights', + + [Parameter(HelpMessage = 'The name of the container to store call records in the cosmos account.')] + [string] + $CosmosCallRecordsContainerName = 'records', + + [Parameter(HelpMessage = 'The name of the existing Kusto cluster to use.')] + [string] + $ExistingKustoClusterName, + + [Parameter(HelpMessage = 'The name of the database in the Kusto cluster.')] + [string] + $KustoCallRecordsDatabaseName = 'CallRecordInsights', + + [Parameter(HelpMessage = 'The name of the table to store processed call records in the Kusto cluster.')] + [string] + $KustoCallRecordsTableName = 'CallRecords', + + [Parameter(HelpMessage = 'The name of the view to store processed call records in the Kusto cluster.')] + [string] + $KustoCallRecordsViewName = $KustoCallRecordsTableName + 'View', + + [Parameter()] + [bool] + $UseEventHubManagedIdentity = $false +) + +if (!(Get-Command -Name az -CommandType Application -ErrorAction SilentlyContinue)) { + Write-Error "Azure CLI is not installed. Please install Azure CLI from https://aka.ms/az-cli." -ErrorAction Stop + return +} + +$AzCommands = @{ + getdeployment = { az deployment group show --resource-group $args[0] --name $args[1] --query properties 2>&1 } + deploybicep = { + param( + [string] + $ResourceGroupName, + [string] + $TemplateFile, + [Hashtable] + $TemplateParameterObject + ) + $parameters = & { + 'deployment' + 'group' + 'create' + '--resource-group' + $ResourceGroupName + '--mode' + 'Incremental' + '--template-file' + $TemplateFile + '--no-prompt' + 'true' + '--no-wait' + '--query' + 'properties' + '--parameters' + $TemplateParameterObject.Keys.ForEach({ + $value = $TemplateParameterObject[$_] + if($value -isnot [string] -and $value -isnot [ValueType] -and ($value -is [Collections.IDictionary] -or $value -is [PSObject])) { + $value = ($value | ConvertTo-Json -Compress -Depth 99).Replace('"','\"') + } + '{0}={1}' -f $_,$value + }) + } + az @parameters 2>&1 + } + getdeploymentoperations = { az deployment operation group list --resource-group $args[0] --name $args[1] --query "[].{provisioningState:properties.provisioningState,targetResource:properties.targetResource.id,statusMessage:properties.statusMessage.error.message}" 2>&1 } + getazsubscription = { az account show --query id 2>&1 } + connect = { az login 2>&1; if ($LASTEXITCODE -eq 0) { az account set --subscription $args[0] 2>&1 } } + getazusername = { az ad signed-in-user show --query userPrincipalName 2>&1 } + getazoid = { az ad signed-in-user show --query id 2>&1 } + getaztenant = { az account show --query tenantId 2>&1 } + getspnobjectid = { az ad sp list --spn $args[0] --query "[].id" 2>&1 } + getresourcegroup = { az group show --name $args[0] 2>&1 } + createresourcegroup = { az group create --name $args[0] --location $args[1] 2>&1 } + getaadapproleassignments = { az rest --method get --url "https://graph.microsoft.com/v1.0/servicePrincipals/$($args[0])/appRoleAssignments" 2>&1 } + addaadapproleassignment = { + $request = @{ + principalId = $args[0] + resourceId = $args[1] + appRoleId = $args[2] + } + $body = ($request | ConvertTo-Json -Compress).Replace('"', '\"') + az rest --method post --url "https://graph.microsoft.com/v1.0/servicePrincipals/$($args[0])/appRoleAssignments" --body "$body" 2>&1 + } + getwebappdeployment = { az webapp log deployment show --resource-group $args[0] --name $args[1] 2>&1 } + getmasterkey = { az functionapp keys list --resource-group $args[0] --name $args[1] --query masterKey 2>&1 } +} + +function FormatDictionary { + [CmdletBinding()] + param( + [Parameter(Mandatory, Position = 0)] + [IDictionary] + $Hashtable + ) + $sb = [StringBuilder]::new('@{') + $first = $true + foreach ($key in $Hashtable.psbase.Keys) { + if (!$first) { $null = $sb.Append(';') } + $first = $false + $null = $sb.AppendFormat('{0}=', (FormatItem $key -UnquoteIfValid)).Append((FormatItem $Hashtable[$key])) + } + return $sb.Append('}').ToString() +} + +function FormatItem { + [CmdletBinding()] + param( + [Parameter(Mandatory, Position = 0)] + [AllowNull()] + [object] + $Item, + + [switch] + $UnquoteIfValid + ) + if ($null -eq $Item) { + return '$null' + } + if ($Item -is [string]) { + if (!$UnquoteIfValid -or [Regex]::IsMatch($key, '[^\dA-Za-z_]')) { + return "'{0}'" -f $Item.Replace("'", "''") + } + return $Item + } + if ($Item -is [Guid]) { + return "[Guid]::Parse('{0}')" -f $Item + } + if ($Item -is [bool]) { + return '${0}' -f $Item.ToString().ToLowerInvariant() + } + if ($Item -is [IDictionary]) { + return FormatDictionary $Item + } + if ($Item -is [ICollection]) { + $sb = [StringBuilder]::new('@(') + $first = $true + foreach ($value in $Item) { + if (!$first) { $null = $sb.Append(',') } + $first = $false + $null = $sb.Append((FormatItem $value)) + } + return $sb.Append(')').ToString() + } + return $Item.ToString() +} + +function TryExecuteMethod { + [CmdletBinding()] + param( + [Parameter(Mandatory, Position = 0)] + [string] + $MethodName, + + [Parameter(ValueFromRemainingArguments)] + [object[]] + $Replacements + ) + $Result = $null + $GeneratedErrors = $null + try { + $Expression = $AzCommands[$MethodName] + $DebugString = "{$($Expression.ToString().Trim())}.Invoke($(FormatItem $Replacements))" + Write-Verbose $DebugString + $Result = $Expression.Invoke($Replacements) | Where-Object { + if ($_ -isnot [ErrorRecord]) { + return $true + } + $er = if($_.Exception -is [RemoteException]) { $_ } else { $_.ErrorRecord } + $message = $er.Exception.Message + Write-Verbose "stderr: $message" + if (![string]::IsNullOrEmpty($message) -and !$message.StartsWith('WARNING:') -and !$message.Contains('You are using cryptography on a 32-bit Python on a 64-bit Windows Operating System.')) { + if ($null -eq $GeneratedErrors) { $GeneratedErrors = [List[ErrorRecord]]@() } + $GeneratedErrors.Add($_) + } + return $false + } | ConvertFrom-Json + } + catch { + if ($null -eq $GeneratedErrors) { $GeneratedErrors = [List[ErrorRecord]]@() } + $GeneratedErrors.Add($_) + $Result = $null + } + if($GeneratedErrors.Count -eq 0) { $GeneratedErrors = $null } + return @($GeneratedErrors, $Result) +} + +function deployifneeded { + param ( + [Parameter(Mandatory, Position = 0)] + [string] + $DeploymentType, + [Parameter(Mandatory, Position = 1)] + [string] + $DeploymentName, + [Parameter(Mandatory, Position = 2)] + [hashtable] + $DeploymentParams, + + [switch] + $SkipDeployment + ) + $StatusMessages = [HashSet[string]]@() + Write-Host "Checking $DeploymentType deployment in resource group '$ResourceGroupName'." + + $Errors, $Deployment = TryExecuteMethod getdeployment $ResourceGroupName $DeploymentName + if (!$SkipDeployment -and (!$Deployment -or $Errors -or ($Deployment.provisioningState -in @('cancelled','failed')))) { + Write-Host "Deploying $DeploymentType to resource group '$ResourceGroupName'. This may take several minutes." + $bicepFile = Join-Path $PSScriptRoot (Join-Path bicep "${DeploymentName}.bicep") + $Errors, $Deployment = TryExecuteMethod deploybicep $ResourceGroupName $bicepFile $DeploymentParams + if ($Errors) { + Write-Error "Failed to create $DeploymentType in resource group '$ResourceGroupName'. Please ensure you have access to the subscription and try again." + $Errors | ForEach-Object { Write-Error -ErrorRecord $_ } + return $null + } + Start-Sleep -Seconds (Get-Random -Minimum 10 -Maximum 30) + } + $First = $true + while ($Deployment.provisioningState -ne 'succeeded') { + if (!$First) { Start-Sleep -Seconds (Get-Random -Minimum 10 -Maximum 30) } + $First = $false + $Errors, $Deployment = TryExecuteMethod getdeployment $ResourceGroupName $DeploymentName + if ($Errors) { + Write-Error "Could not get $DeploymentType deployment in resource group '$ResourceGroupName'. Please ensure you have access to the subscription and try again." + $Errors | ForEach-Object { Write-Error -ErrorRecord $_ } + return $null + } + $state = $Deployment.provisioningState.ToLower() + $JobStatus = "$DeploymentType deployment is $state." + if ($StatusMessages.Add($JobStatus)) { + Write-Host $JobStatus + } + $Errors, $OperationState = TryExecuteMethod getdeploymentoperations $ResourceGroupName $DeploymentName + if (!$Errors) { + @($OperationState | Sort-Object -Property provisioningState, targetResource).ForEach({ + if (!$_.targetResource) { return } + $verb = if ($_.provisioningState.EndsWith('ed')) { 'has' } else { 'is' } + $Message = "Deploy Resource: $($_.targetResource.Split('/providers/',2)[1]) $verb $($_.provisioningState)." + if ($StatusMessages.Add($Message)) { + $Color = if ($Message -match 'has Succeeded') { + 'Green' + } elseif ($Message -match 'has Failed') { + 'Red' + } else { + 'White' + } + Write-Host $Message -ForegroundColor $Color + if ($_.provisioningState -eq 'Failed') { + Write-Warning "$($_.statusMessage)" + } + } + }) + } + $Errors = $null + switch ($state) { + 'cancelled' { + Write-Warning "$DeploymentType in resource group '$ResourceGroupName' deployment was cancelled! Please try again." + return $null + } + 'failed' { + Write-Error "$DeploymentType deployment in resource group '$ResourceGroupName' failed. Please ensure you have access to the subscription and try again." + return $null + } + } + } + Write-Host "$DeploymentType has been deployed successfully." -ForegroundColor Green + Write-Host + return $Deployment +} + +# Try to get current signed-in subscription id, we'll use this to determine if we need to connect all together or connect to a different subscription +Write-Host "Ensuring we are connected to subscription '$SubscriptionId'." +$Errors, $ConnectedSubscriptionId = TryExecuteMethod getazsubscription + +if ($Errors -or $null -eq $ConnectedSubscriptionId -or $ConnectedSubscriptionId -ne $SubscriptionId) { + Write-Host "Connecting to subscription '$SubscriptionId'. Please login if prompted." + $Errors, $null = TryExecuteMethod connect $SubscriptionId + if ($Errors) { + Write-Error "Failed to connect to subscription '$SubscriptionId'. Please ensure you have access to the subscription and try again." + return + } +} +# Get Logged In User +$Errors, $AdminUser = TryExecuteMethod getazusername +if ($Errors) { + Write-Host "Connecting to subscription '$SubscriptionId'. Please login if prompted." + $Errors, $null = TryExecuteMethod connect $SubscriptionId + if ($Errors) { + Write-Error "Failed to get identity of signed in user! Please ensure you are signed in and try again." + $Errors | ForEach-Object { Write-Error -ErrorRecord $_ } + return + } + $Errors, $AdminUser = TryExecuteMethod getazusername + if ($Errors) { + Write-Error "Failed to get identity of signed in user! Please ensure you are signed in and try again." + $Errors | ForEach-Object { Write-Error -ErrorRecord $_ } + return + } +} +$Errors, $AdminOID = TryExecuteMethod getazoid +if ($Errors) { + Write-Error "Failed to get identity of signed in user! Please ensure you are signed in and try again." + $Errors | ForEach-Object { Write-Error -ErrorRecord $_ } + return +} +$Errors, $TenantId = TryExecuteMethod getaztenant +if ($Errors) { + Write-Error "Failed to get tenant id for subscription '$SubscriptionId'. Please ensure you have access to the subscription and try again." + $Errors | ForEach-Object { Write-Error -ErrorRecord $_ } + return +} +Write-Host "Connected to subscription '$SubscriptionId' in tenant '$TenantId' as '$AdminUser'." -ForegroundColor Green +Write-Host + +if ([string]::IsNullOrEmpty($TenantDomain)) { + $TenantDomain = $AdminUser.Split('@')[1] +} + +# Try to get the SPN OID for the Graph Events Change Tracking app +Write-Host "Getting SPN object id for the Microsoft Graph Change Tracking app." +$Errors, $GraphChangeTrackingSPNObjectId = TryExecuteMethod getspnobjectid '0bf30f3b-4a52-48df-9a82-234910c4a086' +if ($Errors) { + Write-Error "Failed to get the SPN object id for the Microsoft Graph Change Tracking app. Please ensure you have access to the tenant and try again." + $Errors | ForEach-Object { Write-Error -ErrorRecord $_ } + return +} +if ($GraphChangeTrackingSPNObjectId -isnot [string]) { $GraphChangeTrackingSPNObjectId = $GraphChangeTrackingSPNObjectId[0] } +Write-Host "SPN object id for the Microsoft Graph Change Tracking app is '$GraphChangeTrackingSPNObjectId'." -ForegroundColor Green +Write-Host + +# Try to get the resource group, if it doesn't exist, create it +Write-Host "Checking if resource group '$ResourceGroupName' exists." +$null, $ResourceGroup = TryExecuteMethod getresourcegroup $ResourceGroupName +if ($null -eq $ResourceGroup) { + Write-Host "Creating resource group '$ResourceGroupName' in location '$Location'." + $Errors, $null = TryExecuteMethod createresourcegroup $ResourceGroupName $Location + if ($Errors) { + Write-Error "Failed to create resource group '$ResourceGroupName' in location '$Location'. Please ensure you have access to the subscription and try again." + $Errors | ForEach-Object { Write-Error -ErrorRecord $_ } + return + } +} +Write-Host "Resource group '$ResourceGroupName' exists." -ForegroundColor Green +Write-Host + +$Deployment = deployifneeded 'Solution' deploy (@{ + baseResourceName = $BaseResourceName + deploymentSize = $DeploymentSize + location = $Location + gitRepoUrl = $GitRepoUrl + gitBranch = $GitBranch + tenantDomain = $TenantDomain + cosmosAccountName = $CosmosAccountName + cosmosCallRecordsDatabaseName = $CosmosCallRecordsDatabaseName + cosmosCallRecordsContainerName = $CosmosCallRecordsContainerName + existingKustoClusterName = $ExistingKustoClusterName + kustoCallRecordsDatabaseName = $KustoCallRecordsDatabaseName + kustoCallRecordsTableName = $KustoCallRecordsTableName + graphChangeTrackingSPNObjectId = $GraphChangeTrackingSPNObjectId + useEventHubManagedIdentity = $UseEventHubManagedIdentity +}) +if (!$Deployment) { return } + +$appPrincipalprincipalId = $Deployment.outputs.appPrincipalprincipalId.value +$functionName = $Deployment.outputs.functionName.value +$appDomain = $Deployment.outputs.appDomain.value + +Write-Host "Getting SPN object id for Microsoft Graph." +$Errors, $MicrosoftGraphSpn = TryExecuteMethod getspnobjectid '00000003-0000-0000-c000-000000000000' +if ($Errors) { + Write-Error "Failed to get the SPN object id for Microsoft Graph. Please ensure you have access to the tenant and try again." + $Errors | ForEach-Object { Write-Error -ErrorRecord $_ } + return +} +if ($MicrosoftGraphSpn -isnot [string]) { $MicrosoftGraphSpn = $MicrosoftGraphSpn[0] } +Write-Host "SPN object id for Microsoft Graph is '$MicrosoftGraphSpn'." -ForegroundColor Green + +Write-Host "Configuring Function App Identity with required permissions." +$Errors, $CurrentPermissions = TryExecuteMethod getaadapproleassignments $appPrincipalprincipalId +$GraphPerms = $null +if ($CurrentPermissions.value) { + $GraphPerms = $CurrentPermissions.value.Where({ $_.resourceId -eq $MicrosoftGraphSpn }).appRoleId +} +$Permissions = @('df021288-bdef-4463-88db-98f22de89214', '45bbb07e-7321-4fd7-a8f6-3ff27e6a81c8') +foreach ($perm in $Permissions) { + if ($GraphPerms -and $GraphPerms.Contains($perm)) { + Write-Host "App role '$perm' is already assigned to Service Principal '$appPrincipalprincipalId'." + Write-Verbose "Existing Perms: $(ConvertTo-Json $GraphPerms -Compress)" + continue + } + Write-Host "Adding app role '$perm' to Service Principal '$appPrincipalprincipalId'." + $Errors, $null = TryExecuteMethod addaadapproleassignment $appPrincipalprincipalId $MicrosoftGraphSpn $perm + if ($Errors) { + Write-Error "Failed to add app role '$perm' to Service Principal '$appPrincipalprincipalId'. Please ensure you have access to the tenant and try again." + $Errors | ForEach-Object { Write-Error -ErrorRecord $_ } + return + } +} +Write-Host "Function App Identity has been configured with required permissions." -ForegroundColor Green +Write-Host + +Write-Host "Waiting for function app '$functionName' to finish deployment." +$deployed = $false +while (!$deployed) { + $Errors, $CurrentDeploymentLogs = TryExecuteMethod getwebappdeployment $ResourceGroupName $functionName + if ($Errors) { + Write-Error "Failed to get deployment logs for function app '$functionName'. Please ensure you have access to the subscription and try again." + $Errors | ForEach-Object { Write-Error -ErrorRecord $_ } + return + } + $latestmessage = if ($null -ne $CurrentDeploymentLogs) { $CurrentDeploymentLogs[-1].message } else { '' } + if ($latestmessage -cmatch 'Deployment Failed.') { + $detailsUrl = $CurrentDeploymentLogs.Where({$_.details_url},'First',1)[0].details_url -replace '(?<=logs)/[^/]+$' + Write-Error "Failed to deploy function app '$functionName'. See $detailsUrl for more details." + return + } + $deployed = $latestmessage -match '^\s*deployment\s+successful\.\s*$' + if (!$deployed) { Start-Sleep -Seconds 10 } +} + +Write-Host "Function app '$functionName' has been deployed successfully." -ForegroundColor Green +Write-Host + +Write-Host 'Getting the master function key to bootstrap the function.' +$Errors, $Key = TryExecuteMethod getmasterkey $ResourceGroupName $functionName +if ($Errors) { + Write-Error "Failed to get master key for function app '$functionName'." + $Errors | ForEach-Object { Write-Error -ErrorRecord $_ } + return +} + +$SubscriptionFunctionUrl = "https://${appDomain}/api/subscription" +$retryInterval = 15 +$RetryCount = 0 +$MaxRetries = 30 +$RetriableErrors = @(500) +try { + Write-Host "Triggering function to add the Call Records Graph Subscription (${SubscriptionFunctionUrl})." + while ($true) { + try { + $null = Invoke-RestMethod -Uri $SubscriptionFunctionUrl -Method Post -Headers @{ 'x-functions-key' = $Key } -Verbose:$false -ErrorAction Stop + break + } + catch { + if ($_.Exception.Response.StatusCode -notin $RetriableErrors -or ++$RetryCount -gt $MaxRetries) { + throw + } + Write-Host "Application is not yet authorized to add the Call Records Graph Subscription, awaiting app role propagation, retrying in $retryInterval seconds." -ForegroundColor Yellow + Start-Sleep -Seconds $retryInterval + $retryInterval = [Math]::Min(($retryInterval * 2), (2 * 60)) + } + } + Write-Host "Triggering function to add the Call Records Graph Subscription completed successfully." -ForegroundColor Green +} +catch { + if ($_.Exception.Response.StatusCode -notin $RetriableErrors) { + Write-Error "Failed to trigger function to add the Call Records Graph Subscription." + Write-Error -ErrorRecord $_ + return + } + Write-Host "Failed to trigger function to add the Call Records Graph Subscription. The application is running but is not yet authorized to add the Call Records Graph Subscription. Try again later." -ForegroundColor Yellow +} + +$HealthFunctionUrl = "https://${appDomain}/api/health" +try { + Write-Host "Getting Health of deployed function (${HealthFunctionUrl})." + $HealthState = Invoke-RestMethod -Uri $HealthFunctionUrl -Headers @{ 'x-functions-key' = $Key } -Verbose:$false -ErrorAction Stop + Set-Variable -Name 'HealthState' -Value $HealthState -Scope Global + Write-Host '$HealthState contains the health of the deployed function.' + if ($HealthState.healthy) { + Write-Host "App deployment is healthy" -ForegroundColor Green + } + else { + Write-Host "App deployment is not healthy" -ForegroundColor Red + Write-Host "HealthState: `n$(ConvertTo-Json -InputObject $HealthState -ErrorAction SilentlyContinue -Depth 10)" + return + } +} +catch { + Write-Error "Failed to get health of deployed function." + Write-Error -ErrorRecord $_ + return +} +Write-Host + +Write-Host "Function deployed to https://${appDomain}/" + +Write-Host "Deployment complete." -ForegroundColor Green \ No newline at end of file diff --git a/deploy/resourcemanager/template.json b/deploy/resourcemanager/template.json new file mode 100644 index 0000000..5e899e5 --- /dev/null +++ b/deploy/resourcemanager/template.json @@ -0,0 +1,1727 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.25.3.34343", + "templateHash": "2662921431620975723" + } + }, + "parameters": { + "baseResourceName": { + "type": "string", + "defaultValue": "[resourceGroup().name]", + "minLength": 3, + "maxLength": 24 + }, + "deploymentSize": { + "type": "string", + "defaultValue": "Production", + "allowedValues": [ + "DevTest", + "Production", + "RestrictedProduction" + ] + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "The Azure region that's right for you. Not every resource is available in every region." + } + }, + "gitRepoUrl": { + "type": "string", + "defaultValue": "https://github.com/Microsoft/CallRecordInsights.git", + "metadata": { + "description": "The URL to the git repository to deploy." + } + }, + "gitBranch": { + "type": "string", + "defaultValue": "main", + "metadata": { + "description": "The branch of the git repository to deploy." + } + }, + "tenantDomain": { + "type": "string", + "metadata": { + "description": "The domain of the tenant that will be monitored for Call Records." + } + }, + "cosmosAccountName": { + "type": "string", + "defaultValue": "[format('{0}cdb', parameters('baseResourceName'))]", + "metadata": { + "description": "The name of the cosmos account to use." + } + }, + "cosmosCallRecordsDatabaseName": { + "type": "string", + "defaultValue": "callrecordinsights", + "metadata": { + "description": "The name of the database to store call records in the cosmos account." + } + }, + "cosmosCallRecordsContainerName": { + "type": "string", + "defaultValue": "records", + "metadata": { + "description": "The name of the container to store call records in the cosmos account." + } + }, + "existingKustoClusterName": { + "type": "string", + "defaultValue": "NOEXISTINGKUSTOCLUSTER", + "metadata": { + "description": "The name of the existing Kusto cluster to use." + } + }, + "kustoCallRecordsDatabaseName": { + "type": "string", + "defaultValue": "CallRecordInsights", + "metadata": { + "description": "The name of the database in the Kusto cluster." + } + }, + "kustoCallRecordsTableName": { + "type": "string", + "defaultValue": "CallRecords", + "metadata": { + "description": "The name of the table to store processed call records in the Kusto cluster." + } + }, + "graphChangeTrackingSPNObjectId": { + "type": "string", + "minLength": 36, + "maxLength": 36, + "metadata": { + "description": "The GUID of the Graph Change Tracking Service Principal for the Subscription's tenant." + } + }, + "useEventHubManagedIdentity": { + "type": "bool", + "defaultValue": false + } + }, + "resources": [ + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "kustoDeploy", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "deploymentType": { + "value": "[parameters('deploymentSize')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "databaseName": { + "value": "[parameters('kustoCallRecordsDatabaseName')]" + }, + "existingKustoClusterName": { + "value": "[parameters('existingKustoClusterName')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.25.3.34343", + "templateHash": "5023612052478866940" + } + }, + "parameters": { + "clusterNamePrefix": { + "type": "string", + "defaultValue": "crinsights", + "metadata": { + "description": "The base name to use for the resources that will be provisioned." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Location for all resources." + } + }, + "deploymentType": { + "type": "string", + "defaultValue": "Production", + "allowedValues": [ + "Production", + "RestrictedProduction", + "DevTest" + ], + "metadata": { + "description": "The type of deployment. Production is a standard deployment. DevTest is a smaller deployment with no SLA." + } + }, + "databaseName": { + "type": "string", + "defaultValue": "CallRecordInsights", + "metadata": { + "description": "The name of the Kusto database." + } + }, + "existingKustoClusterName": { + "type": "string", + "defaultValue": "NOEXISTINGKUSTOCLUSTER", + "metadata": { + "description": "The name of the existing Kusto cluster to use." + } + }, + "identity": { + "type": "string", + "defaultValue": "SystemAssigned", + "metadata": { + "description": "The type of identity to assign to the cluster. SystemAssigned is the default. None will not assign an identity. UserAssigned will assign the identity specified in the identity parameter." + } + } + }, + "variables": { + "clusterConfigurations": { + "DevTest": { + "cluster": { + "sku": { + "name": "Dev(No SLA)_Standard_E2a_v4", + "tier": "Basic", + "capacity": 1 + }, + "properties": { + "enableAutoStop": true + } + }, + "database": { + "properties": { + "softDeletePeriod": "P180D", + "hotCachePeriod": "P7D" + } + } + }, + "Production": { + "cluster": { + "sku": { + "name": "Standard_E2ads_v5", + "tier": "Standard", + "capacity": 2 + }, + "properties": {} + }, + "database": { + "properties": { + "softDeletePeriod": "P365D", + "hotCachePeriod": "P31D" + } + } + }, + "RestrictedProduction": { + "cluster": { + "sku": { + "name": "Standard_E2ads_v5", + "tier": "Standard", + "capacity": 2 + }, + "properties": {} + }, + "database": { + "properties": { + "softDeletePeriod": "P365D", + "hotCachePeriod": "P31D" + } + } + } + }, + "clusterIdentity": "[if(or(equals(parameters('identity'), 'SystemAssigned'), equals(parameters('identity'), 'None')), createObject('type', parameters('identity')), createObject('type', 'UserAssigned', 'userAssignedIdentities', createObject(format('{0}', parameters('identity')), createObject())))]", + "input": "[parameters('clusterNamePrefix')]", + "validChars": [ + "alpha", + "numeric" + ], + "validFirstChars": [ + "alpha", + "numeric" + ], + "validEndChars": [ + "alpha", + "numeric" + ], + "maxLength": 24, + "upper": [ + "A", + "B", + "C", + "D", + "E", + "F", + "G", + "H", + "I", + "J", + "K", + "L", + "M", + "N", + "O", + "P", + "Q", + "R", + "S", + "T", + "U", + "V", + "W", + "X", + "Y", + "Z" + ], + "lower": [ + "a", + "b", + "c", + "d", + "e", + "f", + "g", + "h", + "i", + "j", + "k", + "l", + "m", + "n", + "o", + "p", + "q", + "r", + "s", + "t", + "u", + "v", + "w", + "x", + "y", + "z" + ], + "charSets": { + "upper": "[variables('upper')]", + "lower": "[variables('lower')]", + "alpha": "[concat(variables('upper'), variables('lower'))]", + "numeric": [ + "0", + "1", + "2", + "3", + "4", + "5", + "6", + "7", + "8", + "9" + ], + "hyphen": [ + "-" + ], + "underscore": [ + "_" + ], + "period": [ + "." + ] + }, + "validCharSet": "[flatten(map(variables('validChars'), lambda('s', variables('charSets')[lambdaVariables('s')])))]", + "validFirstCharSet": "[flatten(map(variables('validFirstChars'), lambda('s', variables('charSets')[lambdaVariables('s')])))]", + "validEndCharSet": "[flatten(map(variables('validEndChars'), lambda('s', variables('charSets')[lambdaVariables('s')])))]", + "caseShifted": "[toLower(format('{0}{1}', variables('input'), uniqueString(resourceGroup().id)))]", + "cleanedUnique": "[reduce(map(range(0, sub(length(variables('caseShifted')), 1)), lambda('i', substring(variables('caseShifted'), lambdaVariables('i'), 1))), '', lambda('c', 'n', format('{0}{1}', lambdaVariables('c'), if(and(equals(lambdaVariables('c'), '-'), equals(lambdaVariables('n'), '-')), '', lambdaVariables('n')))))]", + "indexedChars": "[items(toObject(range(0, length(variables('cleanedUnique'))), lambda('i', format('{0}', lambdaVariables('i'))), lambda('i', substring(variables('cleanedUnique'), lambdaVariables('i'), 1))))]", + "firstIndexedChar": "[sort(filter(variables('indexedChars'), lambda('c', contains(variables('validFirstCharSet'), lambdaVariables('c').value))), lambda('c', 'n', less(int(lambdaVariables('c').key), int(lambdaVariables('n').key))))[0]]", + "endIndexedChar": "[sort(filter(variables('indexedChars'), lambda('c', and(and(greater(int(lambdaVariables('c').key), int(variables('firstIndexedChar').key)), and(greater(variables('maxLength'), -1), less(int(lambdaVariables('c').key), add(int(variables('firstIndexedChar').key), variables('maxLength'))))), contains(variables('validEndCharSet'), lambdaVariables('c').value)))), lambda('c', 'n', greater(int(lambdaVariables('c').key), int(lambdaVariables('n').key))))[0]]", + "validIndexedChars": "[sort(filter(variables('indexedChars'), lambda('c', and(and(greater(int(lambdaVariables('c').key), int(variables('firstIndexedChar').key)), less(int(lambdaVariables('c').key), int(variables('endIndexedChar').key))), contains(variables('validCharSet'), lambdaVariables('c').value)))), lambda('c', 'n', less(int(lambdaVariables('c').key), int(lambdaVariables('n').key))))]", + "clusterResourceName": "[format('{0}{1}{2}', variables('firstIndexedChar').value, reduce(variables('validIndexedChars'), '', lambda('c', 'n', format('{0}{1}', lambdaVariables('c'), lambdaVariables('n').value))), variables('endIndexedChar').value)]", + "existing": "[and(not(empty(trim(parameters('existingKustoClusterName')))), not(equals(parameters('existingKustoClusterName'), 'NOEXISTINGKUSTOCLUSTER')))]" + }, + "resources": [ + { + "condition": "[not(variables('existing'))]", + "type": "Microsoft.Kusto/clusters/databases", + "apiVersion": "2023-08-15", + "name": "[format('{0}/{1}', variables('clusterResourceName'), parameters('databaseName'))]", + "location": "[parameters('location')]", + "properties": "[variables('clusterConfigurations')[parameters('deploymentType')].database.properties]", + "kind": "ReadWrite", + "dependsOn": [ + "[resourceId('Microsoft.Kusto/clusters', variables('clusterResourceName'))]" + ] + }, + { + "condition": "[variables('existing')]", + "type": "Microsoft.Kusto/clusters/databases", + "apiVersion": "2023-08-15", + "name": "[format('{0}/{1}', if(variables('existing'), parameters('existingKustoClusterName'), 'bogus'), parameters('databaseName'))]", + "location": "[parameters('location')]", + "properties": "[variables('clusterConfigurations')[parameters('deploymentType')].database.properties]", + "kind": "ReadWrite" + }, + { + "condition": "[not(variables('existing'))]", + "type": "Microsoft.Kusto/clusters", + "apiVersion": "2023-08-15", + "name": "[variables('clusterResourceName')]", + "location": "[parameters('location')]", + "sku": "[variables('clusterConfigurations')[parameters('deploymentType')].cluster.sku]", + "identity": "[variables('clusterIdentity')]", + "properties": "[variables('clusterConfigurations')[parameters('deploymentType')].cluster.properties]" + } + ], + "outputs": { + "Name": { + "type": "string", + "value": "[if(variables('existing'), parameters('existingKustoClusterName'), variables('clusterResourceName'))]" + }, + "Uri": { + "type": "string", + "value": "[if(variables('existing'), reference(resourceId('Microsoft.Kusto/clusters', parameters('existingKustoClusterName')), '2023-08-15').uri, reference(resourceId('Microsoft.Kusto/clusters', variables('clusterResourceName')), '2023-08-15').uri)]" + }, + "DatabaseName": { + "type": "string", + "value": "[if(variables('existing'), format('{0}/{1}', if(variables('existing'), parameters('existingKustoClusterName'), 'bogus'), parameters('databaseName')), parameters('databaseName'))]" + } + } + } + } + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "cosmosDeploy", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "baseResourceName": { + "value": "[parameters('baseResourceName')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "daysToRetainData": { + "value": 30 + }, + "accountName": { + "value": "[parameters('cosmosAccountName')]" + }, + "databaseName": { + "value": "[parameters('cosmosCallRecordsDatabaseName')]" + }, + "containerName": { + "value": "[parameters('cosmosCallRecordsContainerName')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.25.3.34343", + "templateHash": "994269997504341877" + } + }, + "parameters": { + "baseResourceName": { + "type": "string", + "defaultValue": "[resourceGroup().name]", + "minLength": 3, + "maxLength": 35, + "metadata": { + "description": "The base name to use for the resources that will be provisioned." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "The location to create the resources in." + } + }, + "daysToRetainData": { + "type": "int", + "defaultValue": 30, + "minValue": 1, + "maxValue": 365, + "metadata": { + "description": "The number of days to retain data in the Cosmos DB container." + } + }, + "accountName": { + "type": "string", + "defaultValue": "[format('{0}cdb', parameters('baseResourceName'))]", + "minLength": 3, + "maxLength": 44, + "metadata": { + "description": "The name of the Cosmos DB account to create. Must be between 3 and 44 characters long, and contain only lowercase letters, numbers, and hyphens and start with a letter or number." + } + }, + "databaseName": { + "type": "string", + "defaultValue": "callrecordinsights", + "metadata": { + "description": "The name of the Cosmos DB database to create." + } + }, + "containerName": { + "type": "string", + "defaultValue": "records", + "metadata": { + "description": "The name of the Cosmos DB container to create." + } + } + }, + "resources": [ + { + "type": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers", + "apiVersion": "2023-09-15", + "name": "[format('{0}/{1}/{2}', toLower(parameters('accountName')), parameters('databaseName'), parameters('containerName'))]", + "properties": { + "resource": { + "id": "[parameters('containerName')]", + "partitionKey": { + "paths": [ + "/CallRecordTenantIdContext", + "/CallId" + ], + "kind": "MultiHash", + "version": 2 + }, + "indexingPolicy": { + "automatic": true, + "indexingMode": "consistent", + "includedPaths": [ + { + "path": "/CallRecordTenantIdContext/?" + }, + { + "path": "/CallId/?" + }, + { + "path": "/LastModifiedDateTimeOffset/?" + } + ], + "excludedPaths": [ + { + "path": "/*" + } + ], + "compositeIndexes": [ + [ + { + "path": "/CallRecordTenantIdContext", + "order": "descending" + }, + { + "path": "/CallId", + "order": "descending" + }, + { + "path": "/LastModifiedDateTimeOffset", + "order": "descending" + } + ] + ] + }, + "defaultTtl": "[mul(mul(mul(parameters('daysToRetainData'), 24), 60), 60)]" + } + }, + "dependsOn": [ + "[resourceId('Microsoft.DocumentDB/databaseAccounts/sqlDatabases', toLower(parameters('accountName')), parameters('databaseName'))]" + ] + }, + { + "type": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases", + "apiVersion": "2023-09-15", + "name": "[format('{0}/{1}', toLower(parameters('accountName')), parameters('databaseName'))]", + "properties": { + "resource": { + "id": "[parameters('databaseName')]" + }, + "options": { + "autoscaleSettings": { + "maxThroughput": 1000 + } + } + }, + "dependsOn": [ + "[resourceId('Microsoft.DocumentDB/databaseAccounts', toLower(parameters('accountName')))]" + ] + }, + { + "type": "Microsoft.DocumentDB/databaseAccounts", + "apiVersion": "2023-09-15", + "name": "[toLower(parameters('accountName'))]", + "location": "[parameters('location')]", + "properties": { + "databaseAccountOfferType": "Standard", + "locations": [ + { + "locationName": "[parameters('location')]", + "failoverPriority": 0, + "isZoneRedundant": false + } + ] + } + } + ], + "outputs": { + "cosmosDbAccountName": { + "type": "string", + "value": "[toLower(parameters('accountName'))]" + }, + "databaseName": { + "type": "string", + "value": "[parameters('databaseName')]" + }, + "containerName": { + "type": "string", + "value": "[parameters('containerName')]" + } + } + } + } + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "functionDeploy", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "graphChangeTrackingAppObjectId": { + "value": "[parameters('graphChangeTrackingSPNObjectId')]" + }, + "teamsTenantDomainName": { + "value": "[parameters('tenantDomain')]" + }, + "baseResourceName": { + "value": "[parameters('baseResourceName')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "deploymentType": { + "value": "[parameters('deploymentSize')]" + }, + "cosmosAccountName": { + "value": "[reference(resourceId('Microsoft.Resources/deployments', 'cosmosDeploy'), '2022-09-01').outputs.cosmosDbAccountName.value]" + }, + "callRecordsDatabaseName": { + "value": "[reference(resourceId('Microsoft.Resources/deployments', 'cosmosDeploy'), '2022-09-01').outputs.databaseName.value]" + }, + "callRecordsContainerName": { + "value": "[reference(resourceId('Microsoft.Resources/deployments', 'cosmosDeploy'), '2022-09-01').outputs.containerName.value]" + }, + "useGraphEventHubManagedIdentity": { + "value": "[parameters('useEventHubManagedIdentity')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.25.3.34343", + "templateHash": "7928089187257027743" + } + }, + "parameters": { + "graphChangeTrackingAppObjectId": { + "type": "string", + "minLength": 36, + "maxLength": 36, + "metadata": { + "description": "The object id of the Service Principal for the Graph Change Tracking Application." + } + }, + "teamsTenantDomainName": { + "type": "string", + "metadata": { + "description": "The name of the tenant to monitor" + } + }, + "baseResourceName": { + "type": "string", + "defaultValue": "[resourceGroup().name]", + "minLength": 3, + "maxLength": 35, + "metadata": { + "description": "The base name to use for the resources that will be provisioned. It must start with a letter and contain only letters and numbers. It must be globally unique." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Location for all resources." + } + }, + "deploymentType": { + "type": "string", + "defaultValue": "Production", + "allowedValues": [ + "Production", + "RestrictedProduction", + "DevTest" + ], + "metadata": { + "description": "The type of deployment. Production is a standard deployment. DevTest is a smaller deployment with no SLA." + } + }, + "cosmosAccountName": { + "type": "string", + "defaultValue": "[format('{0}cdb', parameters('baseResourceName'))]", + "minLength": 3, + "maxLength": 44, + "metadata": { + "description": "The name of the Cosmos DB account to create. Must be between 3 and 44 characters long, and contain only lowercase letters, numbers, and hyphens and start with a letter or number." + } + }, + "callRecordsDatabaseName": { + "type": "string", + "defaultValue": "callrecordinsights", + "metadata": { + "description": "The name of the cosmos database that contains the processed call records table." + } + }, + "callRecordsContainerName": { + "type": "string", + "defaultValue": "records", + "metadata": { + "description": "The name of the cosmos container that contains the processed call records." + } + }, + "useSeparateKeyVaultForGraph": { + "type": "bool", + "defaultValue": "[not(equals(parameters('deploymentType'), 'DevTest'))]" + }, + "useGraphEventHubManagedIdentity": { + "type": "bool", + "defaultValue": false + } + }, + "variables": { + "$fxv#0": { + "AzureCloud": [ + "52.159.23.209/32", + "52.159.17.84/32", + "13.78.204.0/32", + "52.147.213.251/32", + "52.147.213.181/32", + "20.127.53.125/32", + "70.37.95.92/32", + "70.37.95.11/32", + "70.37.92.195/32", + "20.9.36.45/32", + "20.9.35.166/32", + "20.9.36.128/32", + "20.96.21.67/32", + "20.69.245.215/32", + "104.46.117.15/32", + "137.135.11.161/32", + "137.135.11.116/32", + "20.253.156.113/32", + "52.159.107.50/32", + "52.159.107.4/32", + "52.159.124.33/32", + "20.98.68.182/32", + "20.98.68.57/32", + "20.98.68.200/32", + "20.171.81.121/32", + "20.25.189.138/32", + "20.171.82.192/32", + "52.142.114.29/32", + "52.142.115.31/32", + "20.223.139.245/32", + "51.124.75.43/32", + "51.124.73.177/32", + "104.40.209.182/32", + "20.199.102.157/32", + "20.199.102.73/32", + "20.216.150.67/32", + "20.91.212.211/32", + "20.91.212.136/32", + "20.91.213.57/32", + "20.44.210.83/32", + "20.44.210.146/32", + "20.212.153.162/32", + "40.80.232.177/32", + "40.80.232.118/32", + "52.231.196.24/32", + "20.48.12.75/32", + "20.48.11.201/32", + "20.89.108.161/32", + "104.215.13.23/32", + "104.215.6.169/32", + "20.89.240.165/32" + ], + "AzureUSGovernment": [ + "52.244.33.45/32", + "52.244.35.174/32", + "52.243.157.104/32", + "52.243.157.105/32", + "52.182.25.254/32", + "52.182.25.110/32", + "52.181.25.67/32", + "52.181.25.66/32", + "52.244.111.156/32", + "52.244.111.170/32", + "52.243.147.249/32", + "52.243.148.19/32", + "52.182.32.51/32", + "52.182.32.143/32", + "52.181.24.199/32", + "52.181.24.220/32" + ], + "AzureChinaCloud": [ + "42.159.72.35/32", + "42.159.72.47/32", + "42.159.180.55/32", + "42.159.180.56/32", + "40.125.138.23/32", + "40.125.136.69/32", + "40.72.155.199/32", + "40.72.155.216/32" + ] + }, + "tenantId": "[subscription().tenantId]", + "tenantDomain": "[parameters('teamsTenantDomainName')]", + "storageAccountName": "[format('callq{0}', uniqueString(toLower(parameters('baseResourceName')), toLower(variables('tenantId'))))]", + "downloadQueueName": "[format('{0}download', toLower(parameters('callRecordsDatabaseName')))]", + "keyvaultName": "[if(greater(length(format('kv{0}', parameters('baseResourceName'))), 24), substring(format('kv{0}', parameters('baseResourceName')), 0, 24), format('kv{0}', parameters('baseResourceName')))]", + "graphKeyVaultName": "[format('g{0}', if(greater(length(variables('keyvaultName')), 23), substring(variables('keyvaultName'), 0, 23), variables('keyvaultName')))]", + "configurations": { + "DevTest": { + "serverfarm": { + "sku": { + "name": "Y1" + } + }, + "storage": { + "sku": { + "name": "Standard_LRS" + }, + "properties": { + "supportsHttpsTrafficOnly": true, + "allowBlobPublicAccess": false, + "minimumTlsVersion": "TLS1_2" + } + }, + "eventHub": { + "sku": { + "name": "Basic" + }, + "properties": { + "disableLocalAuth": "[parameters('useGraphEventHubManagedIdentity')]" + }, + "eventhubs": { + "properties": { + "messageRetentionInDays": 1 + } + } + }, + "functionApp": { + "identity": { + "type": "SystemAssigned" + }, + "properties": { + "clientAffinityEnabled": false, + "httpsOnly": true, + "siteConfig": { + "alwaysOn": false, + "netFrameworkVersion": "v6.0", + "ftpsState": "Disabled" + } + } + }, + "keyvault": { + "properties": { + "tenantId": "[subscription().tenantId]", + "publicNetworkAccess": "Enabled", + "enableRbacAuthorization": true, + "sku": { + "name": "standard", + "family": "A" + } + } + } + }, + "Production": { + "serverfarm": { + "sku": { + "name": "Y1" + } + }, + "storage": { + "sku": { + "name": "Standard_GRS" + }, + "properties": { + "supportsHttpsTrafficOnly": true, + "allowBlobPublicAccess": false, + "minimumTlsVersion": "TLS1_2" + } + }, + "eventHub": { + "sku": { + "name": "Basic" + }, + "properties": { + "disableLocalAuth": "[parameters('useGraphEventHubManagedIdentity')]" + }, + "eventhubs": { + "properties": { + "messageRetentionInDays": 1 + } + } + }, + "functionApp": { + "identity": { + "type": "SystemAssigned" + }, + "properties": { + "clientAffinityEnabled": false, + "httpsOnly": true, + "siteConfig": { + "alwaysOn": false, + "netFrameworkVersion": "v6.0", + "ftpsState": "Disabled" + } + } + }, + "keyvault": { + "properties": { + "tenantId": "[subscription().tenantId]", + "publicNetworkAccess": "Enabled", + "enableRbacAuthorization": true, + "sku": { + "name": "standard", + "family": "A" + } + } + } + }, + "RestrictedProduction": { + "serverfarm": { + "sku": { + "name": "EP1" + } + }, + "storage": { + "sku": { + "name": "Standard_GRS" + }, + "properties": { + "supportsHttpsTrafficOnly": true, + "allowBlobPublicAccess": false, + "minimumTlsVersion": "TLS1_2", + "networkAcls": { + "bypass": "AzureServices", + "defaultAction": "Deny", + "ipRules": [], + "virtualNetworkRules": [ + { + "id": "[resourceId('Microsoft.Network/virtualNetworks/subnets', format('vnet-{0}', resourceGroup().name), 'fnapp-subnet')]", + "action": "Allow" + } + ] + } + } + }, + "eventHub": { + "sku": { + "name": "Standard" + }, + "properties": { + "disableLocalAuth": "[parameters('useGraphEventHubManagedIdentity')]" + } + }, + "functionApp": { + "identity": { + "type": "SystemAssigned" + }, + "properties": { + "clientAffinityEnabled": false, + "httpsOnly": true, + "siteConfig": { + "alwaysOn": false, + "netFrameworkVersion": "v6.0", + "ftpsState": "Disabled" + }, + "virtualNetworkSubnetId": "[resourceId('Microsoft.Network/virtualNetworks/subnets', format('vnet-{0}', resourceGroup().name), 'fnapp-subnet')]" + } + }, + "keyvault": { + "properties": { + "tenantId": "[subscription().tenantId]", + "publicNetworkAccess": "Enabled", + "enableRbacAuthorization": true, + "sku": { + "name": "standard", + "family": "A" + }, + "networkAcls": { + "bypass": "AzureServices", + "defaultAction": "Deny", + "virtualNetworkRules": [ + { + "id": "[resourceId('Microsoft.Network/virtualNetworks/subnets', format('vnet-{0}', resourceGroup().name), 'fnapp-subnet')]" + } + ], + "ipRules": "[if(parameters('useGraphEventHubManagedIdentity'), createArray(), map(variables('graphChangeNotificationSubnets')[environment().name], lambda('s', createObject('value', lambdaVariables('s')))))]" + } + } + } + }, + "Custom": {} + }, + "graphChangeNotificationSubnets": "[variables('$fxv#0')]", + "roleDefinitionId": { + "StorageAccount": { + "Contributor": "17d1049b-9a84-46fb-8f53-869881c3d3ab", + "Queue": { + "Data": { + "Contributor": "974c5e8b-45b9-4653-ba55-5f855dd0fb88" + } + }, + "Blob": { + "Data": { + "Owner": "b7e6dc6d-f1e8-4753-8033-0f276bb0955b" + } + } + }, + "EventHubs": { + "Data": { + "Sender": "2b629674-e913-4c01-ae53-ef4638d8f975", + "Receiver": "a638d3c7-ab3a-418d-83e6-5f17a39d4fde" + } + }, + "KeyVault": { + "Secrets": { + "Officer": "b86a8fe4-44ce-4948-aee5-eccb2c155cd7", + "User": "4633458b-17de-408a-b874-0445c86b69e6" + } + }, + "CosmosDB": { + "Data": { + "Contributor": "00000000-0000-0000-0000-000000000002" + } + } + }, + "neededRoles": { + "functionApp": { + "StorageAccount": [ + "[variables('roleDefinitionId').StorageAccount.Contributor]", + "[variables('roleDefinitionId').StorageAccount.Queue.Data.Contributor]", + "[variables('roleDefinitionId').StorageAccount.Blob.Data.Owner]" + ], + "EventHubs": [ + "[variables('roleDefinitionId').EventHubs.Data.Receiver]" + ], + "KeyVault": [ + "[variables('roleDefinitionId').KeyVault.Secrets.Officer]" + ], + "CosmosDB": [ + "[variables('roleDefinitionId').CosmosDB.Data.Contributor]" + ] + }, + "graphChangeTrackingApp": { + "EventHubs": "[if(parameters('useGraphEventHubManagedIdentity'), createArray(variables('roleDefinitionId').EventHubs.Data.Sender), createArray())]", + "KeyVault": "[if(not(parameters('useGraphEventHubManagedIdentity')), createArray(variables('roleDefinitionId').KeyVault.Secrets.User), createArray())]" + } + } + }, + "resources": [ + { + "condition": "[startsWith(parameters('deploymentType'), 'Restricted')]", + "type": "Microsoft.Network/virtualNetworks/subnets", + "apiVersion": "2022-11-01", + "name": "[format('{0}/{1}', format('vnet-{0}', resourceGroup().name), 'fnapp-subnet')]", + "properties": { + "addressPrefix": "10.0.1.0/24", + "serviceEndpoints": [ + { + "service": "Microsoft.KeyVault", + "locations": [ + "[parameters('location')]" + ] + }, + { + "service": "Microsoft.Storage", + "locations": [ + "[parameters('location')]" + ] + }, + { + "service": "Microsoft.Web", + "locations": [ + "[parameters('location')]" + ] + }, + { + "service": "Microsoft.EventHub", + "locations": [ + "[parameters('location')]" + ] + } + ], + "delegations": [ + { + "name": "fnapp-serverFarms", + "properties": { + "serviceName": "Microsoft.Web/serverFarms" + } + } + ] + }, + "dependsOn": [ + "[resourceId('Microsoft.Network/virtualNetworks', format('vnet-{0}', resourceGroup().name))]" + ] + }, + { + "type": "Microsoft.Storage/storageAccounts/queueServices/queues", + "apiVersion": "2022-09-01", + "name": "[format('{0}/{1}/{2}', variables('storageAccountName'), 'default', variables('downloadQueueName'))]", + "dependsOn": [ + "[resourceId('Microsoft.Storage/storageAccounts/queueServices', variables('storageAccountName'), 'default')]" + ] + }, + { + "type": "Microsoft.Storage/storageAccounts/queueServices", + "apiVersion": "2022-09-01", + "name": "[format('{0}/{1}', variables('storageAccountName'), 'default')]", + "dependsOn": [ + "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]" + ] + }, + { + "condition": "[not(parameters('useGraphEventHubManagedIdentity'))]", + "type": "Microsoft.EventHub/namespaces/eventhubs/authorizationRules", + "apiVersion": "2022-10-01-preview", + "name": "[format('{0}/{1}/{2}', parameters('baseResourceName'), 'graphevents', 'sender')]", + "properties": { + "rights": [ + "Send" + ] + }, + "dependsOn": [ + "[resourceId('Microsoft.EventHub/namespaces/eventhubs', parameters('baseResourceName'), 'graphevents')]" + ] + }, + { + "type": "Microsoft.EventHub/namespaces/eventhubs", + "apiVersion": "2022-10-01-preview", + "name": "[format('{0}/{1}', parameters('baseResourceName'), 'graphevents')]", + "properties": "[variables('configurations')[parameters('deploymentType')].eventHub.eventhubs.properties]", + "dependsOn": [ + "[resourceId('Microsoft.EventHub/namespaces', parameters('baseResourceName'))]", + "[resourceId('Microsoft.Network/virtualNetworks/subnets', format('vnet-{0}', resourceGroup().name), 'fnapp-subnet')]" + ] + }, + { + "condition": "[startsWith(parameters('deploymentType'), 'Restricted')]", + "type": "Microsoft.EventHub/namespaces/networkRuleSets", + "apiVersion": "2022-10-01-preview", + "name": "[format('{0}/{1}', parameters('baseResourceName'), 'default')]", + "properties": { + "publicNetworkAccess": "SecuredByPerimeter", + "trustedServiceAccessEnabled": true, + "defaultAction": "Deny", + "virtualNetworkRules": [ + { + "subnet": { + "id": "[resourceId('Microsoft.Network/virtualNetworks/subnets', format('vnet-{0}', resourceGroup().name), 'fnapp-subnet')]" + } + } + ], + "ipRules": "[map(variables('graphChangeNotificationSubnets')[environment().name], lambda('s', createObject('action', 'Allow', 'ipMask', lambdaVariables('s'))))]" + }, + "dependsOn": [ + "[resourceId('Microsoft.EventHub/namespaces', parameters('baseResourceName'))]", + "[resourceId('Microsoft.Network/virtualNetworks/subnets', format('vnet-{0}', resourceGroup().name), 'fnapp-subnet')]" + ] + }, + { + "type": "Microsoft.Web/sites/config", + "apiVersion": "2022-09-01", + "name": "[format('{0}/{1}', format('{0}-function', parameters('baseResourceName')), 'appsettings')]", + "properties": "[toObject(createArray(createObject('key', 'RenewSubscriptionScheduleCron', 'value', '0 0 */2 * * *'), createObject('key', 'CallRecordsQueueConnection__queueServiceUri', 'value', reference(resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName')), '2022-09-01').primaryEndpoints.queue), createObject('key', 'CallRecordsQueueConnection__credential', 'value', 'managedidentity'), createObject('key', 'CallRecordsToDownloadQueueName', 'value', variables('downloadQueueName')), createObject('key', 'GraphSubscription__NotificationUrl', 'value', if(parameters('useGraphEventHubManagedIdentity'), format('EventHub:{0}/eventhubname/{1}', reference(resourceId('Microsoft.EventHub/namespaces', parameters('baseResourceName')), '2022-10-01-preview').serviceBusEndpoint, 'graphevents'), if(parameters('useSeparateKeyVaultForGraph'), format('EventHub:{0}', reference(resourceId('Microsoft.KeyVault/vaults/secrets', variables('graphKeyVaultName'), 'GraphEventHubConnectionString'), '2023-02-01').secretUri), format('EventHub:{0}', reference(resourceId('Microsoft.KeyVault/vaults/secrets', variables('keyvaultName'), 'GraphEventHubConnectionString'), '2023-02-01').secretUri)))), createObject('key', 'GraphSubscription__Tenants', 'value', variables('tenantDomain')), createObject('key', 'CallRecordInsightsDb__EndpointUri', 'value', reference(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('cosmosAccountName')), '2023-09-15').documentEndpoint), createObject('key', 'CallRecordInsightsDb__DatabaseName', 'value', reference(resourceId('Microsoft.DocumentDB/databaseAccounts/sqlDatabases', parameters('cosmosAccountName'), parameters('callRecordsDatabaseName')), '2023-09-15').resource.id), createObject('key', 'CallRecordInsightsDb__ProcessedContainerName', 'value', reference(resourceId('Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers', parameters('cosmosAccountName'), parameters('callRecordsDatabaseName'), parameters('callRecordsContainerName')), '2023-09-15').resource.id), createObject('key', 'GraphNotificationEventHubName', 'value', 'graphevents'), createObject('key', 'EventHubConnection__fullyQualifiedNamespace', 'value', split(split(reference(resourceId('Microsoft.EventHub/namespaces', parameters('baseResourceName')), '2022-10-01-preview').serviceBusEndpoint, '://')[1], ':')[0]), createObject('key', 'EventHubConnection__credential', 'value', 'managedidentity'), createObject('key', 'AzureWebJobsStorage__accountName', 'value', variables('storageAccountName')), createObject('key', 'AzureWebJobsSecretStorageType', 'value', 'keyvault'), createObject('key', 'AzureWebJobsSecretStorageKeyVaultUri', 'value', reference(resourceId('Microsoft.KeyVault/vaults', variables('keyvaultName')), '2023-02-01').vaultUri), createObject('key', 'FUNCTIONS_EXTENSION_VERSION', 'value', '~4'), createObject('key', 'FUNCTIONS_WORKER_RUNTIME', 'value', 'dotnet'), createObject('key', 'WEBSITE_CONTENTAZUREFILECONNECTIONSTRING', 'value', format('@Microsoft.KeyVault(VaultName={0};SecretName={1})', variables('keyvaultName'), 'StorageAccountConnectionString')), createObject('key', 'WEBSITE_CONTENTSHARE', 'value', toLower(format('{0}-function', parameters('baseResourceName'))))), lambda('o', lambdaVariables('o').key), lambda('o', lambdaVariables('o').value))]", + "dependsOn": [ + "[resourceId('Microsoft.Storage/storageAccounts/queueServices/queues', variables('storageAccountName'), 'default', variables('downloadQueueName'))]", + "[resourceId('Microsoft.EventHub/namespaces', parameters('baseResourceName'))]", + "[resourceId('Microsoft.Web/sites', format('{0}-function', parameters('baseResourceName')))]", + "[resourceId('Microsoft.EventHub/namespaces/eventhubs', parameters('baseResourceName'), 'graphevents')]", + "[resourceId('Microsoft.KeyVault/vaults/secrets', variables('graphKeyVaultName'), 'GraphEventHubConnectionString')]", + "[resourceId('Microsoft.KeyVault/vaults/secrets', variables('keyvaultName'), 'GraphEventHubConnectionString')]", + "[resourceId('Microsoft.KeyVault/vaults', variables('keyvaultName'))]", + "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]", + "[resourceId('Microsoft.KeyVault/vaults/secrets', variables('keyvaultName'), 'StorageAccountConnectionString')]" + ] + }, + { + "type": "Microsoft.KeyVault/vaults/secrets", + "apiVersion": "2023-02-01", + "name": "[format('{0}/{1}', variables('keyvaultName'), 'StorageAccountConnectionString')]", + "properties": { + "value": "[format('DefaultEndpointsProtocol=https;AccountName={0};EndpointSuffix={1};AccountKey={2}', variables('storageAccountName'), environment().suffixes.storage, listkeys(resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName')), '2022-09-01').keys[0].value)]", + "attributes": { + "enabled": true + }, + "contentType": "text/plain" + }, + "dependsOn": [ + "[resourceId('Microsoft.KeyVault/vaults', variables('keyvaultName'))]", + "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]" + ] + }, + { + "condition": "[and(not(parameters('useGraphEventHubManagedIdentity')), not(parameters('useSeparateKeyVaultForGraph')))]", + "type": "Microsoft.KeyVault/vaults/secrets", + "apiVersion": "2023-02-01", + "name": "[format('{0}/{1}', variables('keyvaultName'), 'GraphEventHubConnectionString')]", + "properties": { + "value": "[listkeys(resourceId('Microsoft.EventHub/namespaces/eventhubs/authorizationRules', parameters('baseResourceName'), 'graphevents', 'sender'), '2022-10-01-preview').primaryConnectionString]", + "attributes": { + "enabled": true + }, + "contentType": "text/plain" + }, + "dependsOn": [ + "[resourceId('Microsoft.KeyVault/vaults', variables('keyvaultName'))]", + "[resourceId('Microsoft.EventHub/namespaces/eventhubs/authorizationRules', parameters('baseResourceName'), 'graphevents', 'sender')]" + ] + }, + { + "condition": "[and(and(not(parameters('useGraphEventHubManagedIdentity')), parameters('useSeparateKeyVaultForGraph')), and(not(parameters('useGraphEventHubManagedIdentity')), parameters('useSeparateKeyVaultForGraph')))]", + "type": "Microsoft.KeyVault/vaults/secrets", + "apiVersion": "2023-02-01", + "name": "[format('{0}/{1}', variables('graphKeyVaultName'), 'GraphEventHubConnectionString')]", + "properties": { + "value": "[listkeys(resourceId('Microsoft.EventHub/namespaces/eventhubs/authorizationRules', parameters('baseResourceName'), 'graphevents', 'sender'), '2022-10-01-preview').primaryConnectionString]", + "attributes": { + "enabled": true + }, + "contentType": "text/plain" + }, + "dependsOn": [ + "[resourceId('Microsoft.KeyVault/vaults', variables('graphKeyVaultName'))]", + "[resourceId('Microsoft.EventHub/namespaces/eventhubs/authorizationRules', parameters('baseResourceName'), 'graphevents', 'sender')]" + ] + }, + { + "condition": "[startsWith(parameters('deploymentType'), 'Restricted')]", + "type": "Microsoft.Network/virtualNetworks", + "apiVersion": "2022-11-01", + "name": "[format('vnet-{0}', resourceGroup().name)]", + "location": "[parameters('location')]", + "properties": { + "addressSpace": { + "addressPrefixes": [ + "10.0.0.0/16" + ] + } + } + }, + { + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2022-09-01", + "name": "[variables('storageAccountName')]", + "location": "[parameters('location')]", + "kind": "Storage", + "sku": "[variables('configurations')[parameters('deploymentType')].storage.sku]", + "properties": "[variables('configurations')[parameters('deploymentType')].storage.properties]", + "dependsOn": [ + "[resourceId('Microsoft.Network/virtualNetworks/subnets', format('vnet-{0}', resourceGroup().name), 'fnapp-subnet')]" + ] + }, + { + "type": "Microsoft.EventHub/namespaces", + "apiVersion": "2022-10-01-preview", + "name": "[parameters('baseResourceName')]", + "location": "[parameters('location')]", + "sku": "[variables('configurations')[parameters('deploymentType')].eventHub.sku]", + "properties": "[variables('configurations')[parameters('deploymentType')].eventHub.properties]", + "dependsOn": [ + "[resourceId('Microsoft.Network/virtualNetworks/subnets', format('vnet-{0}', resourceGroup().name), 'fnapp-subnet')]" + ] + }, + { + "type": "Microsoft.Web/serverfarms", + "apiVersion": "2022-09-01", + "name": "[parameters('baseResourceName')]", + "location": "[parameters('location')]", + "sku": "[variables('configurations')[parameters('deploymentType')].serverfarm.sku]", + "dependsOn": [ + "[resourceId('Microsoft.Network/virtualNetworks/subnets', format('vnet-{0}', resourceGroup().name), 'fnapp-subnet')]" + ] + }, + { + "type": "Microsoft.Web/sites", + "apiVersion": "2022-09-01", + "name": "[format('{0}-function', parameters('baseResourceName'))]", + "location": "[parameters('location')]", + "kind": "functionapp", + "identity": "[variables('configurations')[parameters('deploymentType')].functionApp.identity]", + "properties": "[variables('configurations')[parameters('deploymentType')].functionApp.properties]", + "dependsOn": [ + "[resourceId('Microsoft.Network/virtualNetworks/subnets', format('vnet-{0}', resourceGroup().name), 'fnapp-subnet')]" + ] + }, + { + "type": "Microsoft.KeyVault/vaults", + "apiVersion": "2023-02-01", + "name": "[variables('keyvaultName')]", + "location": "[parameters('location')]", + "properties": "[variables('configurations')[parameters('deploymentType')].keyvault.properties]", + "dependsOn": [ + "[resourceId('Microsoft.Network/virtualNetworks/subnets', format('vnet-{0}', resourceGroup().name), 'fnapp-subnet')]" + ] + }, + { + "condition": "[and(not(parameters('useGraphEventHubManagedIdentity')), parameters('useSeparateKeyVaultForGraph'))]", + "type": "Microsoft.KeyVault/vaults", + "apiVersion": "2023-02-01", + "name": "[variables('graphKeyVaultName')]", + "location": "[parameters('location')]", + "properties": "[variables('configurations')[parameters('deploymentType')].keyvault.properties]", + "dependsOn": [ + "[resourceId('Microsoft.Network/virtualNetworks/subnets', format('vnet-{0}', resourceGroup().name), 'fnapp-subnet')]" + ] + }, + { + "copy": { + "name": "functionAppStorageRoleAssignment", + "count": "[length(variables('neededRoles').functionApp.StorageAccount)]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Storage/storageAccounts/{0}', variables('storageAccountName'))]", + "name": "[guid(resourceId('Microsoft.Web/sites', format('{0}-function', parameters('baseResourceName'))), variables('neededRoles').functionApp.StorageAccount[copyIndex()], resourceGroup().id)]", + "properties": { + "roleDefinitionId": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', variables('neededRoles').functionApp.StorageAccount[copyIndex()])]", + "principalId": "[reference(resourceId('Microsoft.Web/sites', format('{0}-function', parameters('baseResourceName'))), '2022-09-01', 'full').identity.principalId]", + "principalType": "ServicePrincipal" + }, + "dependsOn": [ + "[resourceId('Microsoft.Web/sites', format('{0}-function', parameters('baseResourceName')))]", + "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]" + ] + }, + { + "copy": { + "name": "functionAppEventHubsRoleAssignment", + "count": "[length(variables('neededRoles').functionApp.EventHubs)]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.EventHub/namespaces/{0}/eventhubs/{1}', parameters('baseResourceName'), 'graphevents')]", + "name": "[guid(resourceId('Microsoft.Web/sites', format('{0}-function', parameters('baseResourceName'))), variables('neededRoles').functionApp.EventHubs[copyIndex()], resourceGroup().id)]", + "properties": { + "roleDefinitionId": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', variables('neededRoles').functionApp.EventHubs[copyIndex()])]", + "principalId": "[reference(resourceId('Microsoft.Web/sites', format('{0}-function', parameters('baseResourceName'))), '2022-09-01', 'full').identity.principalId]", + "principalType": "ServicePrincipal" + }, + "dependsOn": [ + "[resourceId('Microsoft.Web/sites', format('{0}-function', parameters('baseResourceName')))]", + "[resourceId('Microsoft.EventHub/namespaces/eventhubs', parameters('baseResourceName'), 'graphevents')]" + ] + }, + { + "copy": { + "name": "functionAppKeyVaultRoleAssignment", + "count": "[length(variables('neededRoles').functionApp.KeyVault)]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.KeyVault/vaults/{0}', variables('keyvaultName'))]", + "name": "[guid(resourceId('Microsoft.Web/sites', format('{0}-function', parameters('baseResourceName'))), variables('neededRoles').functionApp.KeyVault[copyIndex()], resourceGroup().id)]", + "properties": { + "roleDefinitionId": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', variables('neededRoles').functionApp.KeyVault[copyIndex()])]", + "principalId": "[reference(resourceId('Microsoft.Web/sites', format('{0}-function', parameters('baseResourceName'))), '2022-09-01', 'full').identity.principalId]", + "principalType": "ServicePrincipal" + }, + "dependsOn": [ + "[resourceId('Microsoft.Web/sites', format('{0}-function', parameters('baseResourceName')))]", + "[resourceId('Microsoft.KeyVault/vaults', variables('keyvaultName'))]" + ] + }, + { + "copy": { + "name": "functionAppCosmosDBRoleAssignment", + "count": "[length(variables('neededRoles').functionApp.CosmosDB)]" + }, + "type": "Microsoft.DocumentDB/databaseAccounts/sqlRoleAssignments", + "apiVersion": "2023-09-15", + "name": "[format('{0}/{1}', parameters('cosmosAccountName'), guid(resourceId('Microsoft.Web/sites', format('{0}-function', parameters('baseResourceName'))), variables('neededRoles').functionApp.CosmosDB[copyIndex()], resourceGroup().id))]", + "properties": { + "roleDefinitionId": "[resourceId('Microsoft.DocumentDB/databaseAccounts/sqlRoleDefinitions', parameters('cosmosAccountName'), variables('neededRoles').functionApp.CosmosDB[copyIndex()])]", + "principalId": "[reference(resourceId('Microsoft.Web/sites', format('{0}-function', parameters('baseResourceName'))), '2022-09-01', 'full').identity.principalId]", + "scope": "[replace(resourceId('Microsoft.DocumentDB/databaseAccounts/sqlDatabases', parameters('cosmosAccountName'), parameters('callRecordsDatabaseName')), '/sqlDatabases/', '/dbs/')]" + }, + "dependsOn": [ + "[resourceId('Microsoft.Web/sites', format('{0}-function', parameters('baseResourceName')))]" + ] + }, + { + "copy": { + "name": "graphChangeTrackingAppRoleAssignment", + "count": "[length(variables('neededRoles').graphChangeTrackingApp.EventHubs)]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.EventHub/namespaces/{0}/eventhubs/{1}', parameters('baseResourceName'), 'graphevents')]", + "name": "[guid(parameters('graphChangeTrackingAppObjectId'), variables('neededRoles').graphChangeTrackingApp.EventHubs[copyIndex()], resourceGroup().id)]", + "properties": { + "roleDefinitionId": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', variables('neededRoles').graphChangeTrackingApp.EventHubs[copyIndex()])]", + "principalId": "[parameters('graphChangeTrackingAppObjectId')]", + "principalType": "ServicePrincipal" + }, + "dependsOn": [ + "[resourceId('Microsoft.EventHub/namespaces/eventhubs', parameters('baseResourceName'), 'graphevents')]" + ] + }, + { + "copy": { + "name": "graphChangeTrackingAppKeyVaultRoleAssignment", + "count": "[length(variables('neededRoles').graphChangeTrackingApp.KeyVault)]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "name": "[guid(parameters('graphChangeTrackingAppObjectId'), variables('neededRoles').graphChangeTrackingApp.KeyVault[copyIndex()], resourceGroup().id)]", + "properties": { + "roleDefinitionId": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', variables('neededRoles').graphChangeTrackingApp.KeyVault[copyIndex()])]", + "principalId": "[parameters('graphChangeTrackingAppObjectId')]", + "principalType": "ServicePrincipal" + }, + "dependsOn": [ + "[resourceId('Microsoft.KeyVault/vaults/secrets', variables('graphKeyVaultName'), 'GraphEventHubConnectionString')]", + "[resourceId('Microsoft.KeyVault/vaults/secrets', variables('keyvaultName'), 'GraphEventHubConnectionString')]" + ] + } + ], + "outputs": { + "keyVaultName": { + "type": "string", + "value": "[variables('keyvaultName')]" + }, + "appDomain": { + "type": "string", + "value": "[reference(resourceId('Microsoft.Web/sites', format('{0}-function', parameters('baseResourceName'))), '2022-09-01').defaultHostName]" + }, + "functionName": { + "type": "string", + "value": "[format('{0}-function', parameters('baseResourceName'))]" + }, + "functionAppIdentity": { + "type": "object", + "value": "[reference(resourceId('Microsoft.Web/sites', format('{0}-function', parameters('baseResourceName'))), '2022-09-01', 'full').identity]" + }, + "functionAppSubnetId": { + "type": "string", + "value": "[if(equals(parameters('deploymentType'), 'RestrictedProduction'), reference(resourceId('Microsoft.Web/sites', format('{0}-function', parameters('baseResourceName'))), '2022-09-01').virtualNetworkSubnetId, '')]" + } + } + } + }, + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', 'cosmosDeploy')]" + ] + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "kustoConfigure", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "clusterName": { + "value": "[reference(resourceId('Microsoft.Resources/deployments', 'kustoDeploy'), '2022-09-01').outputs.Name.value]" + }, + "cosmosAccountName": { + "value": "[reference(resourceId('Microsoft.Resources/deployments', 'cosmosDeploy'), '2022-09-01').outputs.cosmosDbAccountName.value]" + }, + "callRecordsDatabaseName": { + "value": "[reference(resourceId('Microsoft.Resources/deployments', 'cosmosDeploy'), '2022-09-01').outputs.databaseName.value]" + }, + "callRecordsContainerName": { + "value": "[reference(resourceId('Microsoft.Resources/deployments', 'cosmosDeploy'), '2022-09-01').outputs.containerName.value]" + }, + "databaseName": { + "value": "[parameters('kustoCallRecordsDatabaseName')]" + }, + "tableName": { + "value": "[parameters('kustoCallRecordsTableName')]" + }, + "viewName": { + "value": "[format('{0}View', parameters('kustoCallRecordsTableName'))]" + }, + "callRecordsFunctionName": { + "value": "[format('{0}Func', parameters('kustoCallRecordsTableName'))]" + }, + "location": { + "value": "[parameters('location')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.25.3.34343", + "templateHash": "7102274191347685" + } + }, + "parameters": { + "clusterName": { + "type": "string", + "metadata": { + "description": "The name of the Kusto cluster." + } + }, + "cosmosAccountName": { + "type": "string", + "metadata": { + "description": "The name of the Cosmos DB account that will be used to store the call records." + } + }, + "callRecordsDatabaseName": { + "type": "string", + "defaultValue": "callrecordinsights", + "metadata": { + "description": "The name of the Cosmos DB database that will be used to store the call records." + } + }, + "callRecordsContainerName": { + "type": "string", + "defaultValue": "records", + "metadata": { + "description": "The name of the Cosmos DB container that will be used to store the call records." + } + }, + "databaseName": { + "type": "string", + "defaultValue": "CallRecordInsights", + "metadata": { + "description": "The name of the Kusto database." + } + }, + "tableName": { + "type": "string", + "defaultValue": "CallRecords", + "metadata": { + "description": "The name of the table to create." + } + }, + "viewName": { + "type": "string", + "defaultValue": "[format('{0}View', parameters('tableName'))]", + "metadata": { + "description": "The name of the view to create." + } + }, + "callRecordsFunctionName": { + "type": "string", + "defaultValue": "[format('{0}Func', parameters('tableName'))]", + "metadata": { + "description": "The name of the get call records function to create." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]" + }, + "updateTag": { + "type": "string", + "defaultValue": "[newGuid()]" + } + }, + "variables": { + "$fxv#0": ".create table ##TABLE_NAME## (\r\n CallRecordTenantIdContext: string,\r\n CallId: guid, SessionId: guid, StreamId: string, StreamDirection: string, MediaLabel: string,\r\n CallStartTime: datetime, CallEndTime: datetime, SessionStartTime: datetime, SessionEndTime: datetime,\r\n LastModifiedDateTimeOffset: datetime, CallType: string, JoinWebUrl: string, VideoCodec: string,\r\n AudioCodec: string, WasMediaBypassed: bool, FailureStage: string, FailureReason: string,\r\n PacketUtilization: long, AverageBandwidthEstimate: long, AverageJitter: timespan, MaxJitter: timespan,\r\n AverageRoundTripTime: timespan, MaxRoundTripTime: timespan, AverageAudioNetworkJitter: timespan,\r\n MaxAudioNetworkJitter: timespan, AverageAudioDegradation: real, AveragePacketLossRate: real,\r\n MaxPacketLossRate: real, PostForwardErrorCorrectionPacketLossRate: real,\r\n AverageRatioOfConcealedSamples: real, MaxRatioOfConcealedSamples: real,\r\n LowVideoProcessingCapabilityRatio: real, AverageVideoFrameRate: real, AverageReceivedFrameRate: real,\r\n LowFrameRateRatio: real, AverageVideoPacketLossRate: real, AverageVideoFrameLossPercentage: real,\r\n Organizer_UserDisplayName: string, Organizer_UserId: guid, Organizer_UserTenantId: guid,\r\n Organizer_ApplicationInstanceDisplayName: string, Organizer_ApplicationInstanceId: guid,\r\n Organizer_ApplicationInstanceTenantId: guid, Organizer_GuestDisplayName: string,\r\n Organizer_GuestId: guid, Organizer_GuestTenantId: guid, Organizer_PhoneDisplayName: string,\r\n Organizer_PhoneId: string, Organizer_PhoneTenantId: guid, Organizer_OnPremisesDisplayName: string,\r\n Organizer_OnPremisesId: guid, Organizer_OnPremisesTenantId: guid,\r\n Organizer_EncryptedDisplayName: string, Organizer_EncryptedId: guid,\r\n Organizer_EncryptedTenantId: guid, Organizer_AcsUserDisplayName: string, Organizer_AcsUserId: guid,\r\n Organizer_AcsUserTenantId: guid, Organizer_SpoolUserDisplayName: string, Organizer_SpoolUserId: guid,\r\n Organizer_SpoolUserTenantId: guid, Organizer_AcsApplicationInstanceDisplayName: string,\r\n Organizer_AcsApplicationInstanceId: guid, Organizer_AcsApplicationInstanceTenantId: guid,\r\n Organizer_SpoolApplicationInstanceDisplayName: string, Organizer_SpoolApplicationInstanceId: guid,\r\n Organizer_SpoolApplicationInstanceTenantId: guid, Callee_UserDisplayName: string, Callee_UserId: guid,\r\n Callee_UserTenantId: guid, Callee_ApplicationInstanceDisplayName: string,\r\n Callee_ApplicationInstanceId: guid, Callee_ApplicationInstanceTenantId: guid,\r\n Callee_GuestDisplayName: string, Callee_GuestId: guid, Callee_GuestTenantId: guid,\r\n Callee_PhoneDisplayName: string, Callee_PhoneId: string, Callee_PhoneTenantId: guid,\r\n Callee_OnPremisesDisplayName: string, Callee_OnPremisesId: guid, Callee_OnPremisesTenantId: guid,\r\n Callee_EncryptedDisplayName: string, Callee_EncryptedId: guid, Callee_EncryptedTenantId: guid,\r\n Callee_AcsUserDisplayName: string, Callee_AcsUserId: guid, Callee_AcsUserTenantId: guid,\r\n Callee_SpoolUserDisplayName: string, Callee_SpoolUserId: guid, Callee_SpoolUserTenantId: guid,\r\n Callee_AcsApplicationInstanceDisplayName: string, Callee_AcsApplicationInstanceId: guid,\r\n Callee_AcsApplicationInstanceTenantId: guid, Callee_SpoolApplicationInstanceDisplayName: string,\r\n Callee_SpoolApplicationInstanceId: guid, Callee_SpoolApplicationInstanceTenantId: guid,\r\n Callee_EndpointType: string, Callee_ProductFamily: string, Callee_Platform: string,\r\n Callee_UserAgentHeaderValue: string, Callee_ServiceRole: string, Callee_ApplicationVersion: string,\r\n Callee_AzureAdAppId: guid, Callee_CommunicationServiceId: guid, Callee_ConnectionType: string,\r\n Callee_ReflexiveIPAddress: string, Callee_Subnet: string, Callee_IpAddress: string,\r\n Callee_MacAddress: string, Callee_LinkSpeed: long, Callee_NetworkTransportProtocol: string,\r\n Callee_Port: int, Callee_RelayIPAddress: string, Callee_RelayPort: int, Callee_DnsSuffix: string,\r\n Callee_TraceRouteHops: string, Callee_BSSID: string, Callee_WifiRadioType: string,\r\n Callee_WifiBand: string, Callee_WifiChannel: int, Callee_WifiSignalStrength: int,\r\n Callee_WifiBatteryCharge: int, Callee_WifiMicrosoftDriver: string,\r\n Callee_WifiMicrosoftDriverVersion: string, Callee_WifiVendorDriver: string,\r\n Callee_WifiVendorDriverVersion: string, Callee_CaptureDeviceName: string,\r\n Callee_CaptureDeviceDriver: string, Callee_RenderDeviceName: string, Callee_RenderDeviceDriver: string,\r\n Callee_SentSignalLevel: real, Callee_SentNoiseLevel: real, Callee_MicGlitchRate: real,\r\n Callee_ReceivedSignalLevel: real, Callee_ReceivedNoiseLevel: real, Callee_SpeakerGlitchRate: real,\r\n Callee_HowlingEventCount: int, Callee_InitialSignalLevelRootMeanSquare: real,\r\n Callee_DeviceGlitchEventRatio: real, Callee_DeviceClippingEventRatio: real,\r\n Callee_LowSpeechToNoiseEventRatio: real, Callee_CaptureNotFunctioningEventRatio: real,\r\n Callee_SentQualityEventRatio: real, Callee_LowSpeechLevelEventRatio: real,\r\n Callee_RenderNotFunctioningEventRatio: real, Callee_ReceivedQualityEventRatio: real,\r\n Callee_RenderZeroVolumeEventRatio: real, Callee_RenderMuteEventRatio: real,\r\n Callee_CpuInsufficentEventRatio: real, Callee_DelayEventRatio: real, Callee_BandwidthLowEventRatio: real,\r\n Callee_FeedbackRating: string, Callee_FeedbackText: string, Callee_FeedbackTokens: string,\r\n Caller_UserDisplayName: string, Caller_UserId: guid, Caller_UserTenantId: guid,\r\n Caller_ApplicationInstanceDisplayName: string, Caller_ApplicationInstanceId: guid,\r\n Caller_ApplicationInstanceTenantId: guid, Caller_GuestDisplayName: string, Caller_GuestId: guid,\r\n Caller_GuestTenantId: guid, Caller_PhoneDisplayName: string, Caller_PhoneId: string,\r\n Caller_PhoneTenantId: guid, Caller_OnPremisesDisplayName: string, Caller_OnPremisesId: guid,\r\n Caller_OnPremisesTenantId: guid, Caller_EncryptedDisplayName: string, Caller_EncryptedId: guid,\r\n Caller_EncryptedTenantId: guid, Caller_AcsUserDisplayName: string, Caller_AcsUserId: guid,\r\n Caller_AcsUserTenantId: guid, Caller_SpoolUserDisplayName: string, Caller_SpoolUserId: guid,\r\n Caller_SpoolUserTenantId: guid, Caller_AcsApplicationInstanceDisplayName: string,\r\n Caller_AcsApplicationInstanceId: guid, Caller_AcsApplicationInstanceTenantId: guid,\r\n Caller_SpoolApplicationInstanceDisplayName: string, Caller_SpoolApplicationInstanceId: guid,\r\n Caller_SpoolApplicationInstanceTenantId: guid, Caller_EndpointType: string, Caller_ProductFamily: string,\r\n Caller_Platform: string, Caller_UserAgentHeaderValue: string, Caller_ServiceRole: string,\r\n Caller_ApplicationVersion: string, Caller_AzureAdAppId: guid, Caller_CommunicationServiceId: guid,\r\n Caller_ConnectionType: string, Caller_ReflexiveIPAddress: string, Caller_Subnet: string,\r\n Caller_IpAddress: string, Caller_MacAddress: string, Caller_LinkSpeed: long,\r\n Caller_NetworkTransportProtocol: string, Caller_Port: int, Caller_RelayIPAddress: string,\r\n Caller_RelayPort: int, Caller_DnsSuffix: string, Caller_TraceRouteHops: string, Caller_BSSID: string,\r\n Caller_WifiRadioType: string, Caller_WifiBand: string, Caller_WifiChannel: int,\r\n Caller_WifiSignalStrength: int, Caller_WifiBatteryCharge: int, Caller_WifiMicrosoftDriver: string,\r\n Caller_WifiMicrosoftDriverVersion: string, Caller_WifiVendorDriver: string,\r\n Caller_WifiVendorDriverVersion: string, Caller_CaptureDeviceName: string,\r\n Caller_CaptureDeviceDriver: string, Caller_RenderDeviceName: string, Caller_RenderDeviceDriver: string,\r\n Caller_SentSignalLevel: real, Caller_SentNoiseLevel: real, Caller_MicGlitchRate: real,\r\n Caller_ReceivedSignalLevel: real, Caller_ReceivedNoiseLevel: real, Caller_SpeakerGlitchRate: real, \r\n Caller_HowlingEventCount: int, Caller_InitialSignalLevelRootMeanSquare: real,\r\n Caller_DeviceGlitchEventRatio: real, Caller_DeviceClippingEventRatio: real,\r\n Caller_LowSpeechToNoiseEventRatio: real, Caller_CaptureNotFunctioningEventRatio: real,\r\n Caller_SentQualityEventRatio: real, Caller_LowSpeechLevelEventRatio: real,\r\n Caller_RenderNotFunctioningEventRatio: real, Caller_ReceivedQualityEventRatio: real,\r\n Caller_RenderZeroVolumeEventRatio: real, Caller_RenderMuteEventRatio: real,\r\n Caller_CpuInsufficentEventRatio: real, Caller_DelayEventRatio: real, Caller_BandwidthLowEventRatio: real,\r\n Caller_FeedbackRating: string, Caller_FeedbackText: string, Caller_FeedbackTokens: string\r\n)", + "$fxv#1": ".create-or-alter function with (docstring = \"Audio Classifier\",folder = \"PTSScripts\") AudioClassifier(\r\n AverageJitter: timespan, AverageRoundTripTime: timespan, AveragePacketLossRate: real, PacketUtilization: long) {\r\n (AveragePacketLossRate > 0.1 or (AverageRoundTripTime/1ms) > 500 or (AverageJitter/1ms) > 30) and PacketUtilization > 1000\r\n}\r\n\r\n.create-or-alter function with (docstring = \"Video Classifier\",folder = \"PTSScripts\") VideoClassifier(\r\n AverageVideoFrameLossPercentage: real, AverageVideoFrameRate: real, PostForwardErrorCorrectionPacketLossRate: real) { \r\n iif(isnotempty(AverageVideoFrameLossPercentage), \r\n AverageVideoFrameLossPercentage > 50,\r\n iif(isnotempty(AverageVideoFrameRate), \r\n AverageVideoFrameRate < 7,\r\n PostForwardErrorCorrectionPacketLossRate > 0.15\r\n )\r\n )\r\n}\r\n\r\n.create-or-alter function with (docstring = \"VBSS Classifier\",folder = \"PTSScripts\") VBSSClassifier(\r\n AverageVideoFrameLossPercentage: real, AverageVideoFrameRate: real, PostForwardErrorCorrectionPacketLossRate: real) {\r\n iif(isnotempty(AverageVideoFrameLossPercentage),\r\n AverageVideoFrameLossPercentage > 50,\r\n iif(isnotempty(AverageVideoFrameRate),\r\n AverageVideoFrameRate < 2,\r\n PostForwardErrorCorrectionPacketLossRate > 0.15\r\n )\r\n )\r\n}\r\n\r\n.create-or-alter function with (folder = \"PTSScripts\") ApplyClassifiers(\r\n T:(MediaLabel: string, AverageJitter: timespan, AverageRoundTripTime: timespan, AveragePacketLossRate: real, PacketUtilization: long,\r\n AverageVideoFrameLossPercentage: real, AverageVideoFrameRate: real, PostForwardErrorCorrectionPacketLossRate: real)) {\r\n T | extend IsClassifiedPoorStream = case( \r\n MediaLabel has_cs 'audio', AudioClassifier(AverageJitter, AverageRoundTripTime, AveragePacketLossRate, PacketUtilization),\r\n MediaLabel has_cs 'applicationsharing', VBSSClassifier(AverageVideoFrameLossPercentage, AverageVideoFrameRate, PostForwardErrorCorrectionPacketLossRate),\r\n MediaLabel has_cs 'video', VideoClassifier(AverageVideoFrameLossPercentage, AverageVideoFrameRate, PostForwardErrorCorrectionPacketLossRate),\r\n bool(null)\r\n )\r\n}\r\n\r\n.create-or-alter materialized-view with (autoUpdateSchema = true, lookback = 30d) ##VIEW_NAME## on table ##TABLE_NAME## {\r\n table('##TABLE_NAME##')\r\n | summarize take_any(*) by CallRecordTenantIdContext, CallId, SessionId, StreamId, StreamDirection, MediaLabel\r\n}\r\n\r\n.create-or-alter function ##FUNCTION_NAME##(numDays: int = long(-1)) {\r\n ApplyClassifiers(materialized_view('##VIEW_NAME##'))\r\n | where numDays < 0 or CallEndTime >= ago(make_timespan(numDays,0,0,0)\r\n )\r\n}\r\n\r\n.create-or-alter function with (docstring = \"Get All Call Records for a given user in the last {days} days\") GetUserCallRecords(userId: guid, numDays: int = long(-1)) {\r\n ##FUNCTION_NAME##(numDays)\r\n | where Caller_UserId == userId or Callee_UserId == userId\r\n}\r\n\r\n.create-or-alter table ##TABLE_NAME## ingestion json mapping \"CallRecordMappingJsonMapping\"\r\n```\r\n[\r\n {\"column\":\"CallRecordTenantIdContext\",\"datatype\":\"string\",\"path\":\"$.CallRecordTenantIdContext\"},\r\n {\"column\":\"CallId\",\"datatype\":\"guid\",\"path\":\"$.CallId\"},\r\n {\"column\":\"SessionId\",\"datatype\":\"guid\",\"path\":\"$.SessionId\"},\r\n {\"column\":\"StreamId\",\"datatype\":\"string\",\"path\":\"$.StreamId\"},\r\n {\"column\":\"StreamDirection\",\"datatype\":\"string\",\"path\":\"$.StreamDirection\"},\r\n {\"column\":\"MediaLabel\",\"datatype\":\"string\",\"path\":\"$.MediaLabel\"},\r\n {\"column\":\"CallStartTime\",\"datatype\":\"datetime\",\"path\":\"$.CallStartTime\"},\r\n {\"column\":\"CallEndTime\",\"datatype\":\"datetime\",\"path\":\"$.CallEndTime\"},\r\n {\"column\":\"SessionStartTime\",\"datatype\":\"datetime\",\"path\":\"$.SessionStartTime\"},\r\n {\"column\":\"SessionEndTime\",\"datatype\":\"datetime\",\"path\":\"$.SessionEndTime\"},\r\n {\"column\":\"LastModifiedDateTimeOffset\",\"datatype\":\"datetime\",\"path\":\"$.LastModifiedDateTimeOffset\"},\r\n {\"column\":\"CallType\",\"datatype\":\"string\",\"path\":\"$.CallType\"},\r\n {\"column\":\"JoinWebUrl\",\"datatype\":\"string\",\"path\":\"$.JoinWebUrl\"},\r\n {\"column\":\"VideoCodec\",\"datatype\":\"string\",\"path\":\"$.VideoCodec\"},\r\n {\"column\":\"AudioCodec\",\"datatype\":\"string\",\"path\":\"$.AudioCodec\"},\r\n {\"column\":\"WasMediaBypassed\",\"datatype\":\"bool\",\"path\":\"$.WasMediaBypassed\"},\r\n {\"column\":\"FailureStage\",\"datatype\":\"string\",\"path\":\"$.FailureStage\"},\r\n {\"column\":\"FailureReason\",\"datatype\":\"string\",\"path\":\"$.FailureReason\"},\r\n {\"column\":\"PacketUtilization\",\"datatype\":\"long\",\"path\":\"$.PacketUtilization\"},\r\n {\"column\":\"AverageBandwidthEstimate\",\"datatype\":\"long\",\"path\":\"$.AverageBandwidthEstimate\"},\r\n {\"column\":\"AverageJitter\",\"datatype\":\"timespan\",\"path\":\"$.AverageJitter\"},\r\n {\"column\":\"MaxJitter\",\"datatype\":\"timespan\",\"path\":\"$.MaxJitter\"},\r\n {\"column\":\"AverageRoundTripTime\",\"datatype\":\"timespan\",\"path\":\"$.AverageRoundTripTime\"},\r\n {\"column\":\"MaxRoundTripTime\",\"datatype\":\"timespan\",\"path\":\"$.MaxRoundTripTime\"},\r\n {\"column\":\"AverageAudioNetworkJitter\",\"datatype\":\"timespan\",\"path\":\"$.AverageAudioNetworkJitter\"},\r\n {\"column\":\"MaxAudioNetworkJitter\",\"datatype\":\"timespan\",\"path\":\"$.MaxAudioNetworkJitter\"},\r\n {\"column\":\"AverageAudioDegradation\",\"datatype\":\"real\",\"path\":\"$.AverageAudioDegradation\"},\r\n {\"column\":\"AveragePacketLossRate\",\"datatype\":\"real\",\"path\":\"$.AveragePacketLossRate\"},\r\n {\"column\":\"MaxPacketLossRate\",\"datatype\":\"real\",\"path\":\"$.MaxPacketLossRate\"},\r\n {\"column\":\"PostForwardErrorCorrectionPacketLossRate\",\"datatype\":\"real\",\"path\":\"$.PostForwardErrorCorrectionPacketLossRate\"},\r\n {\"column\":\"AverageRatioOfConcealedSamples\",\"datatype\":\"real\",\"path\":\"$.AverageRatioOfConcealedSamples\"},\r\n {\"column\":\"MaxRatioOfConcealedSamples\",\"datatype\":\"real\",\"path\":\"$.MaxRatioOfConcealedSamples\"},\r\n {\"column\":\"LowVideoProcessingCapabilityRatio\",\"datatype\":\"real\",\"path\":\"$.LowVideoProcessingCapabilityRatio\"},\r\n {\"column\":\"AverageVideoFrameRate\",\"datatype\":\"real\",\"path\":\"$.AverageVideoFrameRate\"},\r\n {\"column\":\"AverageReceivedFrameRate\",\"datatype\":\"real\",\"path\":\"$.AverageReceivedFrameRate\"},\r\n {\"column\":\"LowFrameRateRatio\",\"datatype\":\"real\",\"path\":\"$.LowFrameRateRatio\"},\r\n {\"column\":\"AverageVideoPacketLossRate\",\"datatype\":\"real\",\"path\":\"$.AverageVideoPacketLossRate\"},\r\n {\"column\":\"AverageVideoFrameLossPercentage\",\"datatype\":\"real\",\"path\":\"$.AverageVideoFrameLossPercentage\"},\r\n {\"column\":\"Organizer_UserDisplayName\",\"datatype\":\"string\",\"path\":\"$.Organizer_UserDisplayName\"},\r\n {\"column\":\"Organizer_UserId\",\"datatype\":\"guid\",\"path\":\"$.Organizer_UserId\"},\r\n {\"column\":\"Organizer_UserTenantId\",\"datatype\":\"guid\",\"path\":\"$.Organizer_UserTenantId\"},\r\n {\"column\":\"Organizer_ApplicationInstanceDisplayName\",\"datatype\":\"string\",\"path\":\"$.Organizer_ApplicationInstanceDisplayName\"},\r\n {\"column\":\"Organizer_ApplicationInstanceId\",\"datatype\":\"guid\",\"path\":\"$.Organizer_ApplicationInstanceId\"},\r\n {\"column\":\"Organizer_ApplicationInstanceTenantId\",\"datatype\":\"guid\",\"path\":\"$.Organizer_ApplicationInstanceTenantId\"},\r\n {\"column\":\"Organizer_GuestDisplayName\",\"datatype\":\"string\",\"path\":\"$.Organizer_GuestDisplayName\"},\r\n {\"column\":\"Organizer_GuestId\",\"datatype\":\"guid\",\"path\":\"$.Organizer_GuestId\"},\r\n {\"column\":\"Organizer_GuestTenantId\",\"datatype\":\"guid\",\"path\":\"$.Organizer_GuestTenantId\"},\r\n {\"column\":\"Organizer_PhoneDisplayName\",\"datatype\":\"string\",\"path\":\"$.Organizer_PhoneDisplayName\"},\r\n {\"column\":\"Organizer_PhoneId\",\"datatype\":\"string\",\"path\":\"$.Organizer_PhoneId\"},\r\n {\"column\":\"Organizer_PhoneTenantId\",\"datatype\":\"guid\",\"path\":\"$.Organizer_PhoneTenantId\"},\r\n {\"column\":\"Organizer_OnPremisesDisplayName\",\"datatype\":\"string\",\"path\":\"$.Organizer_OnPremisesDisplayName\"},\r\n {\"column\":\"Organizer_OnPremisesId\",\"datatype\":\"guid\",\"path\":\"$.Organizer_OnPremisesId\"},\r\n {\"column\":\"Organizer_OnPremisesTenantId\",\"datatype\":\"guid\",\"path\":\"$.Organizer_OnPremisesTenantId\"},\r\n {\"column\":\"Organizer_EncryptedDisplayName\",\"datatype\":\"string\",\"path\":\"$.Organizer_EncryptedDisplayName\"},\r\n {\"column\":\"Organizer_EncryptedId\",\"datatype\":\"guid\",\"path\":\"$.Organizer_EncryptedId\"},\r\n {\"column\":\"Organizer_EncryptedTenantId\",\"datatype\":\"guid\",\"path\":\"$.Organizer_EncryptedTenantId\"},\r\n {\"column\":\"Organizer_AcsUserDisplayName\",\"datatype\":\"string\",\"path\":\"$.Organizer_AcsUserDisplayName\"},\r\n {\"column\":\"Organizer_AcsUserId\",\"datatype\":\"guid\",\"path\":\"$.Organizer_AcsUserId\"},\r\n {\"column\":\"Organizer_AcsUserTenantId\",\"datatype\":\"guid\",\"path\":\"$.Organizer_AcsUserTenantId\"},\r\n {\"column\":\"Organizer_SpoolUserDisplayName\",\"datatype\":\"string\",\"path\":\"$.Organizer_SpoolUserDisplayName\"},\r\n {\"column\":\"Organizer_SpoolUserId\",\"datatype\":\"guid\",\"path\":\"$.Organizer_SpoolUserId\"},\r\n {\"column\":\"Organizer_SpoolUserTenantId\",\"datatype\":\"guid\",\"path\":\"$.Organizer_SpoolUserTenantId\"},\r\n {\"column\":\"Organizer_AcsApplicationInstanceDisplayName\",\"datatype\":\"string\",\"path\":\"$.Organizer_AcsApplicationInstanceDisplayName\"},\r\n {\"column\":\"Organizer_AcsApplicationInstanceId\",\"datatype\":\"guid\",\"path\":\"$.Organizer_AcsApplicationInstanceId\"},\r\n {\"column\":\"Organizer_AcsApplicationInstanceTenantId\",\"datatype\":\"guid\",\"path\":\"$.Organizer_AcsApplicationInstanceTenantId\"},\r\n {\"column\":\"Organizer_SpoolApplicationInstanceDisplayName\",\"datatype\":\"string\",\"path\":\"$.Organizer_SpoolApplicationInstanceDisplayName\"},\r\n {\"column\":\"Organizer_SpoolApplicationInstanceId\",\"datatype\":\"guid\",\"path\":\"$.Organizer_SpoolApplicationInstanceId\"},\r\n {\"column\":\"Organizer_SpoolApplicationInstanceTenantId\",\"datatype\":\"guid\",\"path\":\"$.Organizer_SpoolApplicationInstanceTenantId\"},\r\n {\"column\":\"Callee_UserDisplayName\",\"datatype\":\"string\",\"path\":\"$.Callee_UserDisplayName\"},\r\n {\"column\":\"Callee_UserId\",\"datatype\":\"guid\",\"path\":\"$.Callee_UserId\"},\r\n {\"column\":\"Callee_UserTenantId\",\"datatype\":\"guid\",\"path\":\"$.Callee_UserTenantId\"},\r\n {\"column\":\"Callee_ApplicationInstanceDisplayName\",\"datatype\":\"string\",\"path\":\"$.Callee_ApplicationInstanceDisplayName\"},\r\n {\"column\":\"Callee_ApplicationInstanceId\",\"datatype\":\"guid\",\"path\":\"$.Callee_ApplicationInstanceId\"},\r\n {\"column\":\"Callee_ApplicationInstanceTenantId\",\"datatype\":\"guid\",\"path\":\"$.Callee_ApplicationInstanceTenantId\"},\r\n {\"column\":\"Callee_GuestDisplayName\",\"datatype\":\"string\",\"path\":\"$.Callee_GuestDisplayName\"},\r\n {\"column\":\"Callee_GuestId\",\"datatype\":\"guid\",\"path\":\"$.Callee_GuestId\"},\r\n {\"column\":\"Callee_GuestTenantId\",\"datatype\":\"guid\",\"path\":\"$.Callee_GuestTenantId\"},\r\n {\"column\":\"Callee_PhoneDisplayName\",\"datatype\":\"string\",\"path\":\"$.Callee_PhoneDisplayName\"},\r\n {\"column\":\"Callee_PhoneId\",\"datatype\":\"string\",\"path\":\"$.Callee_PhoneId\"},\r\n {\"column\":\"Callee_PhoneTenantId\",\"datatype\":\"guid\",\"path\":\"$.Callee_PhoneTenantId\"},\r\n {\"column\":\"Callee_OnPremisesDisplayName\",\"datatype\":\"string\",\"path\":\"$.Callee_OnPremisesDisplayName\"},\r\n {\"column\":\"Callee_OnPremisesId\",\"datatype\":\"guid\",\"path\":\"$.Callee_OnPremisesId\"},\r\n {\"column\":\"Callee_OnPremisesTenantId\",\"datatype\":\"guid\",\"path\":\"$.Callee_OnPremisesTenantId\"},\r\n {\"column\":\"Callee_EncryptedDisplayName\",\"datatype\":\"string\",\"path\":\"$.Callee_EncryptedDisplayName\"},\r\n {\"column\":\"Callee_EncryptedId\",\"datatype\":\"guid\",\"path\":\"$.Callee_EncryptedId\"},\r\n {\"column\":\"Callee_EncryptedTenantId\",\"datatype\":\"guid\",\"path\":\"$.Callee_EncryptedTenantId\"},\r\n {\"column\":\"Callee_AcsUserDisplayName\",\"datatype\":\"string\",\"path\":\"$.Callee_AcsUserDisplayName\"},\r\n {\"column\":\"Callee_AcsUserId\",\"datatype\":\"guid\",\"path\":\"$.Callee_AcsUserId\"},\r\n {\"column\":\"Callee_AcsUserTenantId\",\"datatype\":\"guid\",\"path\":\"$.Callee_AcsUserTenantId\"},\r\n {\"column\":\"Callee_SpoolUserDisplayName\",\"datatype\":\"string\",\"path\":\"$.Callee_SpoolUserDisplayName\"},\r\n {\"column\":\"Callee_SpoolUserId\",\"datatype\":\"guid\",\"path\":\"$.Callee_SpoolUserId\"},\r\n {\"column\":\"Callee_SpoolUserTenantId\",\"datatype\":\"guid\",\"path\":\"$.Callee_SpoolUserTenantId\"},\r\n {\"column\":\"Callee_AcsApplicationInstanceDisplayName\",\"datatype\":\"string\",\"path\":\"$.Callee_AcsApplicationInstanceDisplayName\"},\r\n {\"column\":\"Callee_AcsApplicationInstanceId\",\"datatype\":\"guid\",\"path\":\"$.Callee_AcsApplicationInstanceId\"},\r\n {\"column\":\"Callee_AcsApplicationInstanceTenantId\",\"datatype\":\"guid\",\"path\":\"$.Callee_AcsApplicationInstanceTenantId\"},\r\n {\"column\":\"Callee_SpoolApplicationInstanceDisplayName\",\"datatype\":\"string\",\"path\":\"$.Callee_SpoolApplicationInstanceDisplayName\"},\r\n {\"column\":\"Callee_SpoolApplicationInstanceId\",\"datatype\":\"guid\",\"path\":\"$.Callee_SpoolApplicationInstanceId\"},\r\n {\"column\":\"Callee_SpoolApplicationInstanceTenantId\",\"datatype\":\"guid\",\"path\":\"$.Callee_SpoolApplicationInstanceTenantId\"},\r\n {\"column\":\"Callee_EndpointType\",\"datatype\":\"string\",\"path\":\"$.Callee_EndpointType\"},\r\n {\"column\":\"Callee_ProductFamily\",\"datatype\":\"string\",\"path\":\"$.Callee_ProductFamily\"},\r\n {\"column\":\"Callee_Platform\",\"datatype\":\"string\",\"path\":\"$.Callee_Platform\"},\r\n {\"column\":\"Callee_UserAgentHeaderValue\",\"datatype\":\"string\",\"path\":\"$.Callee_UserAgentHeaderValue\"},\r\n {\"column\":\"Callee_ServiceRole\",\"datatype\":\"string\",\"path\":\"$.Callee_ServiceRole\"},\r\n {\"column\":\"Callee_ApplicationVersion\",\"datatype\":\"string\",\"path\":\"$.Callee_ApplicationVersion\"},\r\n {\"column\":\"Callee_AzureAdAppId\",\"datatype\":\"guid\",\"path\":\"$.Callee_AzureAdAppId\"},\r\n {\"column\":\"Callee_CommunicationServiceId\",\"datatype\":\"guid\",\"path\":\"$.Callee_CommunicationServiceId\"},\r\n {\"column\":\"Callee_ConnectionType\",\"datatype\":\"string\",\"path\":\"$.Callee_ConnectionType\"},\r\n {\"column\":\"Callee_ReflexiveIPAddress\",\"datatype\":\"string\",\"path\":\"$.Callee_ReflexiveIPAddress\"},\r\n {\"column\":\"Callee_Subnet\",\"datatype\":\"string\",\"path\":\"$.Callee_Subnet\"},\r\n {\"column\":\"Callee_IpAddress\",\"datatype\":\"string\",\"path\":\"$.Callee_IpAddress\"},\r\n {\"column\":\"Callee_MacAddress\",\"datatype\":\"string\",\"path\":\"$.Callee_MacAddress\"},\r\n {\"column\":\"Callee_LinkSpeed\",\"datatype\":\"long\",\"path\":\"$.Callee_LinkSpeed\"},\r\n {\"column\":\"Callee_NetworkTransportProtocol\",\"datatype\":\"string\",\"path\":\"$.Callee_NetworkTransportProtocol\"},\r\n {\"column\":\"Callee_Port\",\"datatype\":\"int\",\"path\":\"$.Callee_Port\"},\r\n {\"column\":\"Callee_RelayIPAddress\",\"datatype\":\"string\",\"path\":\"$.Callee_RelayIPAddress\"},\r\n {\"column\":\"Callee_RelayPort\",\"datatype\":\"int\",\"path\":\"$.Callee_RelayPort\"},\r\n {\"column\":\"Callee_DnsSuffix\",\"datatype\":\"string\",\"path\":\"$.Callee_DnsSuffix\"},\r\n {\"column\":\"Callee_TraceRouteHops\",\"datatype\":\"string\",\"path\":\"$.Callee_TraceRouteHops\"},\r\n {\"column\":\"Callee_BSSID\",\"datatype\":\"string\",\"path\":\"$.Callee_BSSID\"},\r\n {\"column\":\"Callee_WifiRadioType\",\"datatype\":\"string\",\"path\":\"$.Callee_WifiRadioType\"},\r\n {\"column\":\"Callee_WifiBand\",\"datatype\":\"string\",\"path\":\"$.Callee_WifiBand\"},\r\n {\"column\":\"Callee_WifiChannel\",\"datatype\":\"int\",\"path\":\"$.Callee_WifiChannel\"},\r\n {\"column\":\"Callee_WifiSignalStrength\",\"datatype\":\"int\",\"path\":\"$.Callee_WifiSignalStrength\"},\r\n {\"column\":\"Callee_WifiBatteryCharge\",\"datatype\":\"int\",\"path\":\"$.Callee_WifiBatteryCharge\"},\r\n {\"column\":\"Callee_WifiMicrosoftDriver\",\"datatype\":\"string\",\"path\":\"$.Callee_WifiMicrosoftDriver\"},\r\n {\"column\":\"Callee_WifiMicrosoftDriverVersion\",\"datatype\":\"string\",\"path\":\"$.Callee_WifiMicrosoftDriverVersion\"},\r\n {\"column\":\"Callee_WifiVendorDriver\",\"datatype\":\"string\",\"path\":\"$.Callee_WifiVendorDriver\"},\r\n {\"column\":\"Callee_WifiVendorDriverVersion\",\"datatype\":\"string\",\"path\":\"$.Callee_WifiVendorDriverVersion\"},\r\n {\"column\":\"Callee_CaptureDeviceName\",\"datatype\":\"string\",\"path\":\"$.Callee_CaptureDeviceName\"},\r\n {\"column\":\"Callee_CaptureDeviceDriver\",\"datatype\":\"string\",\"path\":\"$.Callee_CaptureDeviceDriver\"},\r\n {\"column\":\"Callee_RenderDeviceName\",\"datatype\":\"string\",\"path\":\"$.Callee_RenderDeviceName\"},\r\n {\"column\":\"Callee_RenderDeviceDriver\",\"datatype\":\"string\",\"path\":\"$.Callee_RenderDeviceDriver\"},\r\n {\"column\":\"Callee_SentSignalLevel\",\"datatype\":\"real\",\"path\":\"$.Callee_SentSignalLevel\"},\r\n {\"column\":\"Callee_SentNoiseLevel\",\"datatype\":\"real\",\"path\":\"$.Callee_SentNoiseLevel\"},\r\n {\"column\":\"Callee_MicGlitchRate\",\"datatype\":\"real\",\"path\":\"$.Callee_MicGlitchRate\"},\r\n {\"column\":\"Callee_ReceivedSignalLevel\",\"datatype\":\"real\",\"path\":\"$.Callee_ReceivedSignalLevel\"},\r\n {\"column\":\"Callee_ReceivedNoiseLevel\",\"datatype\":\"real\",\"path\":\"$.Callee_ReceivedNoiseLevel\"},\r\n {\"column\":\"Callee_SpeakerGlitchRate\",\"datatype\":\"real\",\"path\":\"$.Callee_SpeakerGlitchRate\"},\r\n {\"column\":\"Callee_HowlingEventCount\",\"datatype\":\"int\",\"path\":\"$.Callee_HowlingEventCount\"},\r\n {\"column\":\"Callee_InitialSignalLevelRootMeanSquare\",\"datatype\":\"real\",\"path\":\"$.Callee_InitialSignalLevelRootMeanSquare\"},\r\n {\"column\":\"Callee_DeviceGlitchEventRatio\",\"datatype\":\"real\",\"path\":\"$.Callee_DeviceGlitchEventRatio\"},\r\n {\"column\":\"Callee_DeviceClippingEventRatio\",\"datatype\":\"real\",\"path\":\"$.Callee_DeviceClippingEventRatio\"},\r\n {\"column\":\"Callee_LowSpeechToNoiseEventRatio\",\"datatype\":\"real\",\"path\":\"$.Callee_LowSpeechToNoiseEventRatio\"},\r\n {\"column\":\"Callee_CaptureNotFunctioningEventRatio\",\"datatype\":\"real\",\"path\":\"$.Callee_CaptureNotFunctioningEventRatio\"},\r\n {\"column\":\"Callee_SentQualityEventRatio\",\"datatype\":\"real\",\"path\":\"$.Callee_SentQualityEventRatio\"},\r\n {\"column\":\"Callee_LowSpeechLevelEventRatio\",\"datatype\":\"real\",\"path\":\"$.Callee_LowSpeechLevelEventRatio\"},\r\n {\"column\":\"Callee_RenderNotFunctioningEventRatio\",\"datatype\":\"real\",\"path\":\"$.Callee_RenderNotFunctioningEventRatio\"},\r\n {\"column\":\"Callee_ReceivedQualityEventRatio\",\"datatype\":\"real\",\"path\":\"$.Callee_ReceivedQualityEventRatio\"},\r\n {\"column\":\"Callee_RenderZeroVolumeEventRatio\",\"datatype\":\"real\",\"path\":\"$.Callee_RenderZeroVolumeEventRatio\"},\r\n {\"column\":\"Callee_RenderMuteEventRatio\",\"datatype\":\"real\",\"path\":\"$.Callee_RenderMuteEventRatio\"},\r\n {\"column\":\"Callee_CpuInsufficentEventRatio\",\"datatype\":\"real\",\"path\":\"$.Callee_CpuInsufficentEventRatio\"},\r\n {\"column\":\"Callee_DelayEventRatio\",\"datatype\":\"real\",\"path\":\"$.Callee_DelayEventRatio\"},\r\n {\"column\":\"Callee_BandwidthLowEventRatio\",\"datatype\":\"real\",\"path\":\"$.Callee_BandwidthLowEventRatio\"},\r\n {\"column\":\"Callee_FeedbackRating\",\"datatype\":\"string\",\"path\":\"$.Callee_FeedbackRating\"},\r\n {\"column\":\"Callee_FeedbackText\",\"datatype\":\"string\",\"path\":\"$.Callee_FeedbackText\"},\r\n {\"column\":\"Callee_FeedbackTokens\",\"datatype\":\"string\",\"path\":\"$.Callee_FeedbackTokens\"},\r\n {\"column\":\"Caller_UserDisplayName\",\"datatype\":\"string\",\"path\":\"$.Caller_UserDisplayName\"},\r\n {\"column\":\"Caller_UserId\",\"datatype\":\"guid\",\"path\":\"$.Caller_UserId\"},\r\n {\"column\":\"Caller_UserTenantId\",\"datatype\":\"guid\",\"path\":\"$.Caller_UserTenantId\"},\r\n {\"column\":\"Caller_ApplicationInstanceDisplayName\",\"datatype\":\"string\",\"path\":\"$.Caller_ApplicationInstanceDisplayName\"},\r\n {\"column\":\"Caller_ApplicationInstanceId\",\"datatype\":\"guid\",\"path\":\"$.Caller_ApplicationInstanceId\"},\r\n {\"column\":\"Caller_ApplicationInstanceTenantId\",\"datatype\":\"guid\",\"path\":\"$.Caller_ApplicationInstanceTenantId\"},\r\n {\"column\":\"Caller_GuestDisplayName\",\"datatype\":\"string\",\"path\":\"$.Caller_GuestDisplayName\"},\r\n {\"column\":\"Caller_GuestId\",\"datatype\":\"guid\",\"path\":\"$.Caller_GuestId\"},\r\n {\"column\":\"Caller_GuestTenantId\",\"datatype\":\"guid\",\"path\":\"$.Caller_GuestTenantId\"},\r\n {\"column\":\"Caller_PhoneDisplayName\",\"datatype\":\"string\",\"path\":\"$.Caller_PhoneDisplayName\"},\r\n {\"column\":\"Caller_PhoneId\",\"datatype\":\"string\",\"path\":\"$.Caller_PhoneId\"},\r\n {\"column\":\"Caller_PhoneTenantId\",\"datatype\":\"guid\",\"path\":\"$.Caller_PhoneTenantId\"},\r\n {\"column\":\"Caller_OnPremisesDisplayName\",\"datatype\":\"string\",\"path\":\"$.Caller_OnPremisesDisplayName\"},\r\n {\"column\":\"Caller_OnPremisesId\",\"datatype\":\"guid\",\"path\":\"$.Caller_OnPremisesId\"},\r\n {\"column\":\"Caller_OnPremisesTenantId\",\"datatype\":\"guid\",\"path\":\"$.Caller_OnPremisesTenantId\"},\r\n {\"column\":\"Caller_EncryptedDisplayName\",\"datatype\":\"string\",\"path\":\"$.Caller_EncryptedDisplayName\"},\r\n {\"column\":\"Caller_EncryptedId\",\"datatype\":\"guid\",\"path\":\"$.Caller_EncryptedId\"},\r\n {\"column\":\"Caller_EncryptedTenantId\",\"datatype\":\"guid\",\"path\":\"$.Caller_EncryptedTenantId\"},\r\n {\"column\":\"Caller_AcsUserDisplayName\",\"datatype\":\"string\",\"path\":\"$.Caller_AcsUserDisplayName\"},\r\n {\"column\":\"Caller_AcsUserId\",\"datatype\":\"guid\",\"path\":\"$.Caller_AcsUserId\"},\r\n {\"column\":\"Caller_AcsUserTenantId\",\"datatype\":\"guid\",\"path\":\"$.Caller_AcsUserTenantId\"},\r\n {\"column\":\"Caller_SpoolUserDisplayName\",\"datatype\":\"string\",\"path\":\"$.Caller_SpoolUserDisplayName\"},\r\n {\"column\":\"Caller_SpoolUserId\",\"datatype\":\"guid\",\"path\":\"$.Caller_SpoolUserId\"},\r\n {\"column\":\"Caller_SpoolUserTenantId\",\"datatype\":\"guid\",\"path\":\"$.Caller_SpoolUserTenantId\"},\r\n {\"column\":\"Caller_AcsApplicationInstanceDisplayName\",\"datatype\":\"string\",\"path\":\"$.Caller_AcsApplicationInstanceDisplayName\"},\r\n {\"column\":\"Caller_AcsApplicationInstanceId\",\"datatype\":\"guid\",\"path\":\"$.Caller_AcsApplicationInstanceId\"},\r\n {\"column\":\"Caller_AcsApplicationInstanceTenantId\",\"datatype\":\"guid\",\"path\":\"$.Caller_AcsApplicationInstanceTenantId\"},\r\n {\"column\":\"Caller_SpoolApplicationInstanceDisplayName\",\"datatype\":\"string\",\"path\":\"$.Caller_SpoolApplicationInstanceDisplayName\"},\r\n {\"column\":\"Caller_SpoolApplicationInstanceId\",\"datatype\":\"guid\",\"path\":\"$.Caller_SpoolApplicationInstanceId\"},\r\n {\"column\":\"Caller_SpoolApplicationInstanceTenantId\",\"datatype\":\"guid\",\"path\":\"$.Caller_SpoolApplicationInstanceTenantId\"},\r\n {\"column\":\"Caller_EndpointType\",\"datatype\":\"string\",\"path\":\"$.Caller_EndpointType\"},\r\n {\"column\":\"Caller_ProductFamily\",\"datatype\":\"string\",\"path\":\"$.Caller_ProductFamily\"},\r\n {\"column\":\"Caller_Platform\",\"datatype\":\"string\",\"path\":\"$.Caller_Platform\"},\r\n {\"column\":\"Caller_UserAgentHeaderValue\",\"datatype\":\"string\",\"path\":\"$.Caller_UserAgentHeaderValue\"},\r\n {\"column\":\"Caller_ServiceRole\",\"datatype\":\"string\",\"path\":\"$.Caller_ServiceRole\"},\r\n {\"column\":\"Caller_ApplicationVersion\",\"datatype\":\"string\",\"path\":\"$.Caller_ApplicationVersion\"},\r\n {\"column\":\"Caller_AzureAdAppId\",\"datatype\":\"guid\",\"path\":\"$.Caller_AzureAdAppId\"},\r\n {\"column\":\"Caller_CommunicationServiceId\",\"datatype\":\"guid\",\"path\":\"$.Caller_CommunicationServiceId\"},\r\n {\"column\":\"Caller_ConnectionType\",\"datatype\":\"string\",\"path\":\"$.Caller_ConnectionType\"},\r\n {\"column\":\"Caller_ReflexiveIPAddress\",\"datatype\":\"string\",\"path\":\"$.Caller_ReflexiveIPAddress\"},\r\n {\"column\":\"Caller_Subnet\",\"datatype\":\"string\",\"path\":\"$.Caller_Subnet\"},\r\n {\"column\":\"Caller_IpAddress\",\"datatype\":\"string\",\"path\":\"$.Caller_IpAddress\"},\r\n {\"column\":\"Caller_MacAddress\",\"datatype\":\"string\",\"path\":\"$.Caller_MacAddress\"},\r\n {\"column\":\"Caller_LinkSpeed\",\"datatype\":\"long\",\"path\":\"$.Caller_LinkSpeed\"},\r\n {\"column\":\"Caller_NetworkTransportProtocol\",\"datatype\":\"string\",\"path\":\"$.Caller_NetworkTransportProtocol\"},\r\n {\"column\":\"Caller_Port\",\"datatype\":\"int\",\"path\":\"$.Caller_Port\"},\r\n {\"column\":\"Caller_RelayIPAddress\",\"datatype\":\"string\",\"path\":\"$.Caller_RelayIPAddress\"},\r\n {\"column\":\"Caller_RelayPort\",\"datatype\":\"int\",\"path\":\"$.Caller_RelayPort\"},\r\n {\"column\":\"Caller_DnsSuffix\",\"datatype\":\"string\",\"path\":\"$.Caller_DnsSuffix\"},\r\n {\"column\":\"Caller_TraceRouteHops\",\"datatype\":\"string\",\"path\":\"$.Caller_TraceRouteHops\"},\r\n {\"column\":\"Caller_BSSID\",\"datatype\":\"string\",\"path\":\"$.Caller_BSSID\"},\r\n {\"column\":\"Caller_WifiRadioType\",\"datatype\":\"string\",\"path\":\"$.Caller_WifiRadioType\"},\r\n {\"column\":\"Caller_WifiBand\",\"datatype\":\"string\",\"path\":\"$.Caller_WifiBand\"},\r\n {\"column\":\"Caller_WifiChannel\",\"datatype\":\"int\",\"path\":\"$.Caller_WifiChannel\"},\r\n {\"column\":\"Caller_WifiSignalStrength\",\"datatype\":\"int\",\"path\":\"$.Caller_WifiSignalStrength\"},\r\n {\"column\":\"Caller_WifiBatteryCharge\",\"datatype\":\"int\",\"path\":\"$.Caller_WifiBatteryCharge\"},\r\n {\"column\":\"Caller_WifiMicrosoftDriver\",\"datatype\":\"string\",\"path\":\"$.Caller_WifiMicrosoftDriver\"},\r\n {\"column\":\"Caller_WifiMicrosoftDriverVersion\",\"datatype\":\"string\",\"path\":\"$.Caller_WifiMicrosoftDriverVersion\"},\r\n {\"column\":\"Caller_WifiVendorDriver\",\"datatype\":\"string\",\"path\":\"$.Caller_WifiVendorDriver\"},\r\n {\"column\":\"Caller_WifiVendorDriverVersion\",\"datatype\":\"string\",\"path\":\"$.Caller_WifiVendorDriverVersion\"},\r\n {\"column\":\"Caller_CaptureDeviceName\",\"datatype\":\"string\",\"path\":\"$.Caller_CaptureDeviceName\"},\r\n {\"column\":\"Caller_CaptureDeviceDriver\",\"datatype\":\"string\",\"path\":\"$.Caller_CaptureDeviceDriver\"},\r\n {\"column\":\"Caller_RenderDeviceName\",\"datatype\":\"string\",\"path\":\"$.Caller_RenderDeviceName\"},\r\n {\"column\":\"Caller_RenderDeviceDriver\",\"datatype\":\"string\",\"path\":\"$.Caller_RenderDeviceDriver\"},\r\n {\"column\":\"Caller_SentSignalLevel\",\"datatype\":\"real\",\"path\":\"$.Caller_SentSignalLevel\"},\r\n {\"column\":\"Caller_SentNoiseLevel\",\"datatype\":\"real\",\"path\":\"$.Caller_SentNoiseLevel\"},\r\n {\"column\":\"Caller_MicGlitchRate\",\"datatype\":\"real\",\"path\":\"$.Caller_MicGlitchRate\"},\r\n {\"column\":\"Caller_ReceivedSignalLevel\",\"datatype\":\"real\",\"path\":\"$.Caller_ReceivedSignalLevel\"},\r\n {\"column\":\"Caller_ReceivedNoiseLevel\",\"datatype\":\"real\",\"path\":\"$.Caller_ReceivedNoiseLevel\"},\r\n {\"column\":\"Caller_SpeakerGlitchRate\",\"datatype\":\"real\",\"path\":\"$.Caller_SpeakerGlitchRate\"},\r\n {\"column\":\"Caller_HowlingEventCount\",\"datatype\":\"int\",\"path\":\"$.Caller_HowlingEventCount\"},\r\n {\"column\":\"Caller_InitialSignalLevelRootMeanSquare\",\"datatype\":\"real\",\"path\":\"$.Caller_InitialSignalLevelRootMeanSquare\"},\r\n {\"column\":\"Caller_DeviceGlitchEventRatio\",\"datatype\":\"real\",\"path\":\"$.Caller_DeviceGlitchEventRatio\"},\r\n {\"column\":\"Caller_DeviceClippingEventRatio\",\"datatype\":\"real\",\"path\":\"$.Caller_DeviceClippingEventRatio\"},\r\n {\"column\":\"Caller_LowSpeechToNoiseEventRatio\",\"datatype\":\"real\",\"path\":\"$.Caller_LowSpeechToNoiseEventRatio\"},\r\n {\"column\":\"Caller_CaptureNotFunctioningEventRatio\",\"datatype\":\"real\",\"path\":\"$.Caller_CaptureNotFunctioningEventRatio\"},\r\n {\"column\":\"Caller_SentQualityEventRatio\",\"datatype\":\"real\",\"path\":\"$.Caller_SentQualityEventRatio\"},\r\n {\"column\":\"Caller_LowSpeechLevelEventRatio\",\"datatype\":\"real\",\"path\":\"$.Caller_LowSpeechLevelEventRatio\"},\r\n {\"column\":\"Caller_RenderNotFunctioningEventRatio\",\"datatype\":\"real\",\"path\":\"$.Caller_RenderNotFunctioningEventRatio\"},\r\n {\"column\":\"Caller_ReceivedQualityEventRatio\",\"datatype\":\"real\",\"path\":\"$.Caller_ReceivedQualityEventRatio\"},\r\n {\"column\":\"Caller_RenderZeroVolumeEventRatio\",\"datatype\":\"real\",\"path\":\"$.Caller_RenderZeroVolumeEventRatio\"},\r\n {\"column\":\"Caller_RenderMuteEventRatio\",\"datatype\":\"real\",\"path\":\"$.Caller_RenderMuteEventRatio\"},\r\n {\"column\":\"Caller_CpuInsufficentEventRatio\",\"datatype\":\"real\",\"path\":\"$.Caller_CpuInsufficentEventRatio\"},\r\n {\"column\":\"Caller_DelayEventRatio\",\"datatype\":\"real\",\"path\":\"$.Caller_DelayEventRatio\"},\r\n {\"column\":\"Caller_BandwidthLowEventRatio\",\"datatype\":\"real\",\"path\":\"$.Caller_BandwidthLowEventRatio\"},\r\n {\"column\":\"Caller_FeedbackRating\",\"datatype\":\"string\",\"path\":\"$.Caller_FeedbackRating\"},\r\n {\"column\":\"Caller_FeedbackText\",\"datatype\":\"string\",\"path\":\"$.Caller_FeedbackText\"},\r\n {\"column\":\"Caller_FeedbackTokens\",\"datatype\":\"string\",\"path\":\"$.Caller_FeedbackTokens\"}\r\n]\r\n```" + }, + "resources": [ + { + "type": "Microsoft.Kusto/clusters/databases/scripts", + "apiVersion": "2022-12-29", + "name": "[format('{0}/{1}/{2}', parameters('clusterName'), parameters('databaseName'), guid(parameters('tableName'), 'createtable'))]", + "properties": { + "continueOnErrors": false, + "forceUpdateTag": "[parameters('updateTag')]", + "scriptContent": "[replace(replace(replace(variables('$fxv#0'), '##TABLE_NAME##', parameters('tableName')), '##VIEW_NAME##', parameters('viewName')), '##FUNCTION_NAME##', parameters('callRecordsFunctionName'))]" + } + }, + { + "type": "Microsoft.Kusto/clusters/databases/scripts", + "apiVersion": "2022-12-29", + "name": "[format('{0}/{1}/{2}', parameters('clusterName'), parameters('databaseName'), guid(parameters('tableName'), 'configuretable'))]", + "properties": { + "continueOnErrors": false, + "forceUpdateTag": "[parameters('updateTag')]", + "scriptContent": "[replace(replace(replace(variables('$fxv#1'), '##TABLE_NAME##', parameters('tableName')), '##VIEW_NAME##', parameters('viewName')), '##FUNCTION_NAME##', parameters('callRecordsFunctionName'))]" + }, + "dependsOn": [ + "[resourceId('Microsoft.Kusto/clusters/databases/scripts', parameters('clusterName'), parameters('databaseName'), guid(parameters('tableName'), 'createtable'))]" + ] + }, + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "name": "[guid(parameters('clusterName'), parameters('tableName'), 'fbdf93bf-df7d-467e-a4d2-9458aa1360c8')]", + "properties": { + "roleDefinitionId": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'fbdf93bf-df7d-467e-a4d2-9458aa1360c8')]", + "principalId": "[reference(resourceId('Microsoft.Kusto/clusters', parameters('clusterName')), '2022-12-29', 'full').identity.principalId]" + } + }, + { + "type": "Microsoft.DocumentDB/databaseAccounts/sqlRoleAssignments", + "apiVersion": "2023-09-15", + "name": "[format('{0}/{1}', parameters('cosmosAccountName'), guid(parameters('clusterName'), parameters('tableName'), '00000000-0000-0000-0000-000000000001'))]", + "properties": { + "roleDefinitionId": "[resourceId('Microsoft.DocumentDB/databaseAccounts/sqlRoleDefinitions', parameters('cosmosAccountName'), '00000000-0000-0000-0000-000000000001')]", + "principalId": "[reference(resourceId('Microsoft.Kusto/clusters', parameters('clusterName')), '2022-12-29', 'full').identity.principalId]", + "scope": "[replace(replace(resourceId('Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers', parameters('cosmosAccountName'), parameters('callRecordsDatabaseName'), parameters('callRecordsContainerName')), '/sqlDatabases/', '/dbs/'), '/containers/', '/colls/')]" + } + }, + { + "type": "Microsoft.Kusto/clusters/databases/dataConnections", + "apiVersion": "2023-08-15", + "name": "[format('{0}/{1}/{2}', parameters('clusterName'), parameters('databaseName'), format('{0}Ingestion', parameters('tableName')))]", + "location": "[parameters('location')]", + "kind": "CosmosDb", + "properties": { + "cosmosDbAccountResourceId": "[resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('cosmosAccountName'))]", + "cosmosDbDatabase": "[reference(resourceId('Microsoft.DocumentDB/databaseAccounts/sqlDatabases', parameters('cosmosAccountName'), parameters('callRecordsDatabaseName')), '2023-09-15').resource.id]", + "cosmosDbContainer": "[reference(resourceId('Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers', parameters('cosmosAccountName'), parameters('callRecordsDatabaseName'), parameters('callRecordsContainerName')), '2023-09-15').resource.id]", + "managedIdentityResourceId": "[resourceId('Microsoft.Kusto/clusters', parameters('clusterName'))]", + "tableName": "[parameters('tableName')]", + "mappingRuleName": "CallRecordMappingJsonMapping" + }, + "dependsOn": [ + "[resourceId('Microsoft.Authorization/roleAssignments', guid(parameters('clusterName'), parameters('tableName'), 'fbdf93bf-df7d-467e-a4d2-9458aa1360c8'))]", + "[resourceId('Microsoft.DocumentDB/databaseAccounts/sqlRoleAssignments', parameters('cosmosAccountName'), guid(parameters('clusterName'), parameters('tableName'), '00000000-0000-0000-0000-000000000001'))]", + "[resourceId('Microsoft.Kusto/clusters/databases/scripts', parameters('clusterName'), parameters('databaseName'), guid(parameters('tableName'), 'configuretable'))]" + ] + } + ] + } + }, + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', 'cosmosDeploy')]", + "[resourceId('Microsoft.Resources/deployments', 'kustoDeploy')]" + ] + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "codeDeploy", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "functionAppName": { + "value": "[reference(resourceId('Microsoft.Resources/deployments', 'functionDeploy'), '2022-09-01').outputs.functionName.value]" + }, + "gitRepoUrl": { + "value": "[parameters('gitRepoUrl')]" + }, + "gitBranch": { + "value": "[parameters('gitBranch')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.25.3.34343", + "templateHash": "14633294426575691402" + } + }, + "parameters": { + "functionAppName": { + "type": "string", + "metadata": { + "description": "The name of the Azure Function App to deploy to." + } + }, + "gitRepoUrl": { + "type": "string", + "defaultValue": "https://github.com/Microsoft/CallRecordInsights.git", + "metadata": { + "description": "The URL to the GitHub repository to deploy." + } + }, + "gitBranch": { + "type": "string", + "defaultValue": "main", + "metadata": { + "description": "The branch of the GitHub repository to deploy." + } + } + }, + "resources": [ + { + "condition": "[not(empty(parameters('gitRepoUrl')))]", + "type": "Microsoft.Web/sites/sourcecontrols", + "apiVersion": "2022-09-01", + "name": "[format('{0}/{1}', parameters('functionAppName'), 'web')]", + "properties": { + "repoUrl": "[parameters('gitRepoUrl')]", + "branch": "[parameters('gitBranch')]", + "isManualIntegration": true + } + } + ] + } + }, + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', 'functionDeploy')]" + ] + } + ], + "outputs": { + "appPrincipalprincipalId": { + "type": "string", + "value": "[reference(resourceId('Microsoft.Resources/deployments', 'functionDeploy'), '2022-09-01').outputs.functionAppIdentity.value.principalId]" + }, + "functionName": { + "type": "string", + "value": "[reference(resourceId('Microsoft.Resources/deployments', 'functionDeploy'), '2022-09-01').outputs.functionName.value]" + }, + "appDomain": { + "type": "string", + "value": "[reference(resourceId('Microsoft.Resources/deployments', 'functionDeploy'), '2022-09-01').outputs.appDomain.value]" + } + } +} \ No newline at end of file diff --git a/docs/admin-functions.md b/docs/admin-functions.md new file mode 100644 index 0000000..530459d --- /dev/null +++ b/docs/admin-functions.md @@ -0,0 +1,80 @@ +# Admin Functions + +Add info here about how to disable, and notes that none are required post deployment if wanting to eliminate all HTTP Triggers + +Call Record Insights provides several HTTP Triggered functions solely for administrative purposes. + +Each admin function requires the use of the master/host key for authentication. + +--- + +## GetCallRecordAdminFunction +This admin function retrieves a raw call record from Graph + +### URL +`https://cridemo1-function.azurewebsites.net/api/callRecords/ca111dca-111d-ca11-1dca-11ca111dca11/contoso.com?code=` + +### Method +`GET` + +--- + +## AddSubscriptionOrRenewIfExpiredFunction +This admin function creates/renews the subscription to Graph + +### URL +`https://cridemo1-function.azurewebsites.net/api/subscription/contoso.com?code=` + +### Method +`POST` + +--- + +## ManuallyProcessCallIdsFunction +This admin function process a call record with a provided Call-Id. + +### URL +`https://cridemo1-function.azurewebsites.net/api/callRecords?code=` + +### Method +`POST` + +### Body +`["ca111dca-111d-ca11-1dca-11ca111dca11"]` + +### Content-Type +`application/json` + +--- + +## GetCallRecordInsightsHealthFunction +Gets the health state of each component + +### URL +`https://cridemo1-function.azurewebsites.net/api/health?code=` + +### Method +`GET` + +--- + +## GetSubscriptionIdFunction +Gets the Azure subscription Id the deployment is in + +### URL +`https://cridemo1-function.azurewebsites.net/api/subscription/contoso.com?code=` + +### Method +`GET` + +### Result +```json +{ + "id": "0ddba11c-a11a-b1ec-ab00-5eca55e77e1d", + "expirationDateTime": "1/20/2024 10:30:03 AM", + "tenantId": "c0ffee60-0dde-cafc-0ffe-ebadcaffe14e", + "resource": "communications/callRecords", + "changeType": "created,updated", + "notificationUrl": "EventHub:https://kvcridemo1.vault.azure.net/secrets/GraphEventHubConnectionString?tenantId=c0ffee60-0dde-cafc-0ffe-ebadcaffe14e" +} +``` diff --git a/docs/data-explorer-functions-views-queries.md b/docs/data-explorer-functions-views-queries.md new file mode 100644 index 0000000..88ee87e --- /dev/null +++ b/docs/data-explorer-functions-views-queries.md @@ -0,0 +1,3 @@ +# CosmosDB, Kusto Functions, Views and Queries + +\ \ No newline at end of file diff --git a/docs/deployment.md b/docs/deployment.md new file mode 100644 index 0000000..5af067a --- /dev/null +++ b/docs/deployment.md @@ -0,0 +1,174 @@ +# Deployment +Follow the steps below to deploy the application: + +## Retrieve Deployment Scripts + +### Fork Repo (optional) + +> [!WARNING] +> This step is required if you want to make any customizations to the solution being deployed + +![](./media/github-fork.png) + +### Download the zip file containing the source and deployment scripts + +> [!NOTE] +> If you performed the [step above](#fork-repo-optional), this should be done from your new repository + +![](./media/github-download-code.png) + +### Unblock the zip file +This is required to prevent issues with script ps1 script executions. + +![](./media/unblock-file.png) + +### Extract the zip file +The deployment script(s) will be executed from this directory. Make note of where this was stored. + +## Define deployment parameters + +### `[-ResourceGroupName]` \ **Required** +This is the name that is used for the Azure Resource Group that Call Record Insights resources will be deployed to. If this does not exist it will be created. + +### `[-BaseResourceName]` \ +This is the name of which all resources are based upon. If BaseResourceName is not specified ResourceGroupName is used. + +**Default**: [ResourceGroupName](#resourcegroupname-string-required) + +### `[-SubscriptionId]` \ **Required** +This is the subscription id of the subscription to which the application will be deployed. + +### `[-DeploymentSize]` \ +This defines the SKUs of each component (Kusto, Function App, Storage Account). + +Options are: +- DevTest +- Production +- ProductionRestricted + +**Default**: `Production` + +### `[-Location]` \ +This is the Azure region location where the application (and all associated resources) will be deployed. + +[Choose the Right Azure Region for You \| Microsoft Azure](https://azure.microsoft.com/en-us/explore/global-infrastructure/geographies/#overview) + +*Example*: `centralus` + +**Default**: `westus` + +### `[-GitRepoUrl]` \ +This is the GIT Repo URL that you are deploying. + +If you [forked](#fork-repo-optional) the repo, then this is **Required** and must be set to the url hosting your repository + +*Example*: `https://github.com/{organization}/callrecord-insights.git` + +If you are using a private repository, then a Personal Access Token must be created and passed in this parameter + +*Example*: `https://{username}:{PAT}@github.com/{organization}/callrecord-insights.git` + +**Default**: `https://github.com/OfficeDev/microsoft-teams-apps-callrecord-insights.git` + +### `[-GitBranch]` \ +This is the name of the branch of the repository you wish to deploy + +**Default**: `main` + +### `[-TenantDomain]` \ **Required** +This is the domain name associated with your Tenant. + +*Example*: `contoso.com` + +### `[-CosmosAccountName]` \ +The account name used for Cosmos DB. + +**Default**: [BaseResourceName](#baseresourcename-string) + `cdb` + +### `[-CosmosCallRecordsDatabaseName]` \ +The database name used for the Call Records Database in Cosmos DB. + +**Default**: `CallRecordInsights` + +### `[-CosmosCallRecordsContainerName]` \ +The CallRecords container name in Cosmos DB. + +**Default**: `records` + +### `[-ExistingKustoClusterName]` \ +The Kusto cluster name if deploying to an existing KustoCluster + +### `[-KustoCallRecordsDatabaseName]` \ +The database name inside of the Kusto cluster of the Call Records database + +### `[-KustoCallRecordsTableName]` \ +The table name inside of the Kusto database + +### `[-KustoCallRecordsViewName]` \ +The name of the view that de-duplicates records in case of duplication due to updated call record ingestion. + +### `[-UseEventHubManagedIdentity]` \ +Reserved for future use, currently breaks all functionality. + +> [!CAUTION] +> Do not use this parameter + +## Execute deploy.ps1 +Using the parameters defined [above](#define-deployment-parameters) + +*Example:* +```powershell +$DeploymentParameters = @{ + ResourceGroupName = 'cridemo1rg' + BaseResourceName = 'cridemo1' + SubscriptionId = 'ba5eba11-beef-ba5e-ba11-beefba5eba11' + TenantDomain = 'contoso.com' +} +.\deploy.ps1 @DeploymentParameters +``` + +Wait for deployment script to complete + +# Deployment Validation & Verification + +Once deployment steps complete (successfully or unsuccessfully) the deployment script calls the admin function to get the health state of the deployment. The output indicates whether all required services are up and healthy. + +## Deployment Validation +Once the deployment script is completed, the final output will be the deployment health. + +If the output of `$HealthState` is healthy, then you will receive the following message: +**`App deployment is healthy.`** + +### Deployment Health Details +`$HealthState` is the variable which will contain details regarding the health state of the deployment + +![](./media/deploy-ps1-health-state.png) + +#### healthy +This indicates if the deployment is overall healthy or unhealthy. + +#### eventHub +This provides the health status of the EventHub and the EventHub Url + +#### cosmos +This provides the health status of the Cosmos DB and the Cosmos DB Url for the call records db. + +#### downloadQueue +This provides the health status of the Azure Storage Queue and the Azure Storage Queue Url for the download queue. + +#### subscriptions +This provides the health status of the subscription to the Call Records Graph API endpoint and the expiration date of the subscription. + +#### unhealthyServices +Lists all services above that were found to be unhealthy. + +### Check Cosmos DB Ingestion/Data Connection + +From portal.azure.com, +Navigate to Resource Group -> Kusto Cluster -> Databases -> Database -> CosmosDB + +![](./media/data-explorer-portal-database.png) +![](./media/data-explorer-portal-data-connections.png) + +### Check Subscription Status in Graph +![](./media/graph-explorer-list-subscriptions.png) diff --git a/docs/function-configuration-settings.md b/docs/function-configuration-settings.md new file mode 100644 index 0000000..6de0d2f --- /dev/null +++ b/docs/function-configuration-settings.md @@ -0,0 +1,127 @@ +# Configuration Settings + +> [!NOTE] +> This application was designed to use Identity-Based connections wherever possible, and as such, some of the configuration entries look different than other examples of Azure Function implementations. +> See [this](https://learn.microsoft.com/en-us/azure/azure-functions/functions-reference#configure-an-identity-based-connection) for more information + +## `RenewSubscriptionScheduleCron` +This is Cron string for the frequency of renewing the Call Records Notification Subscription from Graph. + +This defaults to `0 0 */2 * * *` or every 2 hours. + +## `CallRecordsQueueConnection__queueServiceUri` +This is the Queue Service Uri of the storage account which contains the download/processing queue. + +This is set by [deployFunction.bicep](../deploy/bicep/deployFunction.bicep) to the primary queue endpoint of the storage account the same template creates. + +## `CallRecordsQueueConnection__credential` +This is the identity used to connect to the [download/processing queue](#callrecordsqueueconnection__queueserviceuri) + +This is set by [deployFunction.bicep](../deploy/bicep/deployFunction.bicep) to `managedidentity`. This should not be changed. + +## `CallRecordsToDownloadQueueName` +This is the name of the storage queue to be used as the download/processing queue. + +This is set by [deployFunction.bicep](../deploy/bicep/deployFunction.bicep) to [KustoCallRecordsDatabaseName](#kustocallrecordsdatabasename-string) + `download` + +## `GraphSubscription__NotificationUrl` +This is the `notificationUrl` used in the Call Records [Subscription](https://learn.microsoft.com/en-us/graph/api/resources/subscription#properties) used by the deployment + +This will be in the form of the Uri for the Key Vault secret holding the Event Hub connection string for use by the Graph Event Notification Service. + +See [Receive change notifications through Azure Event Hubs](https://learn.microsoft.com/en-us/graph/change-notifications-delivery-event-hubs#creating-the-subscription) for more info + +## `GraphSubscription__Tenants` +This is a list of tenants the application is configured to monitor. It can be either a tenantId GUID or configured tenant domain. + +By default, this is set to [TenantDomain](deployment.md#tenantdomain-string-required) + +If [Multi/Cross Tenant](./multi-tenant-deployment.md) deployment is desired, this will be all the monitored tenants, separated by a semi-colon (`;`) + +## `AzureAd` +This section will not be present unless configured manually. +This section is for configuring the app service principal to be used when calling Graph API. +This is only required for [Multi/Cross Tenant](./multi-tenant-deployment.md) deployments, otherwise the managed identity of the function app will be used for all Graph API calls. + +This section should be a valid [MicrosoftIdentityOptions](https://learn.microsoft.com/en-us/dotnet/api/microsoft.identity.web.microsoftidentityoptions) configuration. + +The fields `TenantId`, `ClientId`, `Instance`, and either `ClientCredentials` or `ClientCertificates` are required + +*Example*: +``` +AzureAd__Instance: https://login.microsoftonline.com +AzureAd__TenantId: c0ffee60-0dde-cafc-0ffe-ebadcaffe14e +AzureAd__ClientId: c1d71d1d-ca11-ca11-ca11-defa177ca115 +AzureAd__ClientCredentials__0__SourceType: KeyVault +AzureAd__ClientCredentials__0__KeyVaultUrl: https://kvcridemo1.vault.azure.net +AzureAd__ClientCredentials__0__KeyVaultCertificateName: CRI-DEMO-1-SPN-CERT +``` + +## `CallRecordInsightsDb__EndpointUri` +This is the Document Endpoint of the Cosmos DB Account used to store the flattened call records. + +This is set by [deployFunction.bicep](../deploy/bicep/deployFunction.bicep) to the documentEndpoint of the Cosmos DB Account that was created in [deployCosmos.bicep](../deploy/bicep/deployCosmos.bicep) + +## `CallRecordInsightsDb__DatabaseName` +This is the name of the Cosmos DB database used to store the flattened call records. + +This is set by [deployFunction.bicep](../deploy/bicep/deployFunction.bicep) to the name of the database that was created in [deployCosmos.bicep](../deploy/bicep/deployCosmos.bicep) + +## `CallRecordInsightsDb__ProcessedContainerName` +This is the container in the Cosmos DB database used to store the flattened call records. + +This is set by [deployFunction.bicep](../deploy/bicep/deployFunction.bicep) to the name of the container in the Cosmos DB database that was created in [deployCosmos.bicep](../deploy/bicep/deployCosmos.bicep) + +## `GraphNotificationEventHubName` +This is the Event Hub to which the Graph Event Notifications are sent. + +This is set by [deployFunction.bicep](../deploy/bicep/deployFunction.bicep) to the name of the Event Hub configured in the same template. + +## `EventHubConnection__fullyQualifiedNamespace` +This is the namespace of the Event Hub associated with [GraphNotificationEventHubName](#graphnotificationeventhubname) + +This is used for the identity-based connection from the function app. + +This is set by [deployFunction.bicep](../deploy/bicep/deployFunction.bicep) from the underlying serviceBusEndpoint of the Event Hub configured in the same template. + +## `EventHubConnection__credential` +This is the identity used to connect to the [Event Hub](#eventhubconnection__fullyqualifiednamespace) + +This is set by [deployFunction.bicep](../deploy/bicep/deployFunction.bicep) to `managedidentity`. This should not be changed. + +## `AzureWebJobsStorage__accountName` +This is the name of the storage account used for the function app. + +This is used for the identity-based connection from the function app. + +This is set by [deployFunction.bicep](../deploy/bicep/deployFunction.bicep) and should not be changed. + +## `AzureWebJobsSecretStorageType` +This is the secret storage entry to allow secrets management to occur in Key Vault instead of in the underlying storage account. + +This is set by [deployFunction.bicep](../deploy/bicep/deployFunction.bicep) to `keyvault`. This should not be changed. + +## `AzureWebJobsSecretStorageKeyVaultUri` +This is the secret storage entry to allow secrets management to occur in Key Vault instead of in the underlying storage account. + +This is set by [deployFunction.bicep](../deploy/bicep/deployFunction.bicep) to the Key Vault Uri created for internal use in the same template. + +## `FUNCTIONS_EXTENSION_VERSION` +This is a mandatory Azure Functions configuration entry. + +This is set by [deployFunction.bicep](../deploy/bicep/deployFunction.bicep) to `~4`. This should not be changed. + +## `FUNCTIONS_WORKER_RUNTIME` +This is a mandatory Azure Functions configuration entry. + +This is set by [deployFunction.bicep](../deploy/bicep/deployFunction.bicep) to `dotnet`. This should not be changed. + +## `WEBSITE_CONTENTAZUREFILECONNECTIONSTRING` +This is a mandatory Azure Functions configuration entry. + +This is set by [deployFunction.bicep](../deploy/bicep/deployFunction.bicep) to a key vault reference to the secret containing the storage account connection string, both of which were created in the same template. + +## `WEBSITE_CONTENTSHARE` +This is a mandatory Azure Functions configuration entry. + +This is set by [deployFunction.bicep](../deploy/bicep/deployFunction.bicep) to the name of the function app. \ No newline at end of file diff --git a/docs/high-level-architecture.md b/docs/high-level-architecture.md new file mode 100644 index 0000000..8420f4d --- /dev/null +++ b/docs/high-level-architecture.md @@ -0,0 +1,3 @@ +# High Level Architecture + +![](./media/architecture-diagram.png) \ No newline at end of file diff --git a/docs/media/architecture-diagram.png b/docs/media/architecture-diagram.png new file mode 100644 index 0000000..897545e Binary files /dev/null and b/docs/media/architecture-diagram.png differ diff --git a/docs/media/data-explorer-portal-data-connections.png b/docs/media/data-explorer-portal-data-connections.png new file mode 100644 index 0000000..170da47 Binary files /dev/null and b/docs/media/data-explorer-portal-data-connections.png differ diff --git a/docs/media/data-explorer-portal-database.png b/docs/media/data-explorer-portal-database.png new file mode 100644 index 0000000..59c5252 Binary files /dev/null and b/docs/media/data-explorer-portal-database.png differ diff --git a/docs/media/deploy-ps1-health-state.png b/docs/media/deploy-ps1-health-state.png new file mode 100644 index 0000000..51ad287 Binary files /dev/null and b/docs/media/deploy-ps1-health-state.png differ diff --git a/docs/media/example-azure-resources.png b/docs/media/example-azure-resources.png new file mode 100644 index 0000000..b0a4d13 Binary files /dev/null and b/docs/media/example-azure-resources.png differ diff --git a/docs/media/github-download-code.png b/docs/media/github-download-code.png new file mode 100644 index 0000000..c109e54 Binary files /dev/null and b/docs/media/github-download-code.png differ diff --git a/docs/media/github-fork.png b/docs/media/github-fork.png new file mode 100644 index 0000000..84be8a7 Binary files /dev/null and b/docs/media/github-fork.png differ diff --git a/docs/media/graph-explorer-list-subscriptions.png b/docs/media/graph-explorer-list-subscriptions.png new file mode 100644 index 0000000..8e547d9 Binary files /dev/null and b/docs/media/graph-explorer-list-subscriptions.png differ diff --git a/docs/media/multi-tenant-create-application-1.png b/docs/media/multi-tenant-create-application-1.png new file mode 100644 index 0000000..a27c292 Binary files /dev/null and b/docs/media/multi-tenant-create-application-1.png differ diff --git a/docs/media/multi-tenant-create-application-10.png b/docs/media/multi-tenant-create-application-10.png new file mode 100644 index 0000000..5bbd1ec Binary files /dev/null and b/docs/media/multi-tenant-create-application-10.png differ diff --git a/docs/media/multi-tenant-create-application-11.png b/docs/media/multi-tenant-create-application-11.png new file mode 100644 index 0000000..eb671ab Binary files /dev/null and b/docs/media/multi-tenant-create-application-11.png differ diff --git a/docs/media/multi-tenant-create-application-12.png b/docs/media/multi-tenant-create-application-12.png new file mode 100644 index 0000000..a6cf40a Binary files /dev/null and b/docs/media/multi-tenant-create-application-12.png differ diff --git a/docs/media/multi-tenant-create-application-13.png b/docs/media/multi-tenant-create-application-13.png new file mode 100644 index 0000000..0818d98 Binary files /dev/null and b/docs/media/multi-tenant-create-application-13.png differ diff --git a/docs/media/multi-tenant-create-application-2.png b/docs/media/multi-tenant-create-application-2.png new file mode 100644 index 0000000..8f2d449 Binary files /dev/null and b/docs/media/multi-tenant-create-application-2.png differ diff --git a/docs/media/multi-tenant-create-application-3.png b/docs/media/multi-tenant-create-application-3.png new file mode 100644 index 0000000..c5980cd Binary files /dev/null and b/docs/media/multi-tenant-create-application-3.png differ diff --git a/docs/media/multi-tenant-create-application-4.png b/docs/media/multi-tenant-create-application-4.png new file mode 100644 index 0000000..4d99861 Binary files /dev/null and b/docs/media/multi-tenant-create-application-4.png differ diff --git a/docs/media/multi-tenant-create-application-5.png b/docs/media/multi-tenant-create-application-5.png new file mode 100644 index 0000000..9bb2763 Binary files /dev/null and b/docs/media/multi-tenant-create-application-5.png differ diff --git a/docs/media/multi-tenant-create-application-6.png b/docs/media/multi-tenant-create-application-6.png new file mode 100644 index 0000000..f636f6b Binary files /dev/null and b/docs/media/multi-tenant-create-application-6.png differ diff --git a/docs/media/multi-tenant-create-application-7.png b/docs/media/multi-tenant-create-application-7.png new file mode 100644 index 0000000..8ce8c99 Binary files /dev/null and b/docs/media/multi-tenant-create-application-7.png differ diff --git a/docs/media/multi-tenant-create-application-8.png b/docs/media/multi-tenant-create-application-8.png new file mode 100644 index 0000000..2b3890d Binary files /dev/null and b/docs/media/multi-tenant-create-application-8.png differ diff --git a/docs/media/multi-tenant-create-application-9.png b/docs/media/multi-tenant-create-application-9.png new file mode 100644 index 0000000..30b3f27 Binary files /dev/null and b/docs/media/multi-tenant-create-application-9.png differ diff --git a/docs/media/multi-tenant-grant-consent-1.png b/docs/media/multi-tenant-grant-consent-1.png new file mode 100644 index 0000000..0dd17c7 Binary files /dev/null and b/docs/media/multi-tenant-grant-consent-1.png differ diff --git a/docs/media/multi-tenant-grant-consent-2.png b/docs/media/multi-tenant-grant-consent-2.png new file mode 100644 index 0000000..6a225f0 Binary files /dev/null and b/docs/media/multi-tenant-grant-consent-2.png differ diff --git a/docs/media/multi-tenant-grant-consent-3.png b/docs/media/multi-tenant-grant-consent-3.png new file mode 100644 index 0000000..5df9a46 Binary files /dev/null and b/docs/media/multi-tenant-grant-consent-3.png differ diff --git a/docs/media/multi-tenant-grant-consent-4.png b/docs/media/multi-tenant-grant-consent-4.png new file mode 100644 index 0000000..3748ad0 Binary files /dev/null and b/docs/media/multi-tenant-grant-consent-4.png differ diff --git a/docs/media/multi-tenant-grant-consent-5.png b/docs/media/multi-tenant-grant-consent-5.png new file mode 100644 index 0000000..b0abe86 Binary files /dev/null and b/docs/media/multi-tenant-grant-consent-5.png differ diff --git a/docs/media/multi-tenant-register-service-principal-1.png b/docs/media/multi-tenant-register-service-principal-1.png new file mode 100644 index 0000000..f7ef04e Binary files /dev/null and b/docs/media/multi-tenant-register-service-principal-1.png differ diff --git a/docs/media/unblock-file.png b/docs/media/unblock-file.png new file mode 100644 index 0000000..3bf9b09 Binary files /dev/null and b/docs/media/unblock-file.png differ diff --git a/docs/multi-tenant-deployment.md b/docs/multi-tenant-deployment.md new file mode 100644 index 0000000..9f515a9 --- /dev/null +++ b/docs/multi-tenant-deployment.md @@ -0,0 +1,103 @@ +# Multi/Cross Tenant Deployment + +For the default (and most common) deployment, Call Record Insights is deployed to an Azure Subscription associated with the same Microsoft Entra ID Tenant that is being monitored. + +However, when that shared tenant context is not possible, it is possible to deploy Call Record Insights to work in either a Cross-Tenant or Multi-Tenant configuration. + +Example: + +- Development deployment with Production data being monitored + +- Single deployment with multiple subsidiary tenants being monitored + +Since the default deployment uses Managed Identity for all Microsoft Graph authentication, this will not work, as the identity would only have permissions to access data from the tenant which owns the Identity. + +By using Microsoft Entra ID App authentication, we can authenticate against external tenants that have been properly configured and consented. + +## Create Microsoft Entra ID App Registration (In Deployed Tenant) +### Create a New registration + + + +> [!Note] +> Be sure to select *Accounts in any organizational directory (Any Microsoft Entra ID - Multitenant)* + + + + + +### Configure Microsoft Graph API Permissions + + + + + + + +### Grant admin consent (Optional) + +> [!NOTE] +> This is only necessary if the Microsoft Entra ID Tenant where Call Record Insights is deployed is being monitored +> +> This is unneeded if Call Records for this tenant are unwanted + + + + + +### Create Client Secret + +> [!NOTE] +> Client Certificates can also be used +> +> It is recommended that this is not done via the portal but instead managed and stored within the configured Azure Key Vault used by Call Record Insights + +> [!NOTE] +> If this Secret or Certificate Expires or is revoked, Call Record Insights will no longer be able to monitor Call Records until renewed. + + + + + +## Register Service Principal (In All Monitored Tenants) + +### Create New Service Principal for the newly created App Registration + +```powershell +$MultiTenantAppClientId = 'c0ffee60-0dde-cafc-0ffe-ebadcaffe14e' # This should be the Application (client) ID for the app registration + +Connect-MgGraph -Scopes Application.ReadWrite.All +$NewSPN = New-MgServicePrincipal -AppId $MultiTenantAppClientId + +Write-Host "Go To https://portal.azure.com/#view/Microsoft_AAD_IAM/ManagedAppMenuBlade/~/Permissions/objectId/$($NewSPN.Id)/appId/$MultiTenantAppClientId to grant consent to the application for your tenant." +``` + + + +### Grant consent for the new Service Principal + + + +#### Sign as a Global Administrator + + +#### Verify the Application and Permissions are correct + + +#### After Accepting the Permissions requested + + +#### Refresh To Verify the permissions are consented + + +## Update Call Record Insights Configuration + +### Ensure all monitored domains are present in the [Monitored Tenant List](./function-configuration-settings.md#graphsubscription__tenants). + +If a domain is not listed in this configuration, it **will not be monitored** even if consent has been granted + +If the local tenant is also monitored, be sure to include it in the configuration in addition to any external Tenants. + +### Enable Call Record Insights to use the [App Registration](#create-microsoft-entra-id-app-registration-in-deployed-tenant) + +This is done in the [Graph App Configuration](./function-configuration-settings.md#azuread), refer there for more information and example(s) diff --git a/docs/requirements.md b/docs/requirements.md new file mode 100644 index 0000000..3c12805 --- /dev/null +++ b/docs/requirements.md @@ -0,0 +1,342 @@ +# Requirements + +## Pre-Deployment Requirements +The Call Record Insights application requires the following steps to be completed before deploying. + +- Existing Azure Subscription to deploy to +- Rights to create new resources in Azure Subscription + - See [Deployment Permissions](#deployment-permissions) for details. +- Teams Enabled Users to generate call records + +## Deployment Client Requirements +If using [deploy.ps1](../deploy/deploy.ps1), The workstation performing the deployment requires + +- PowerShell 7.2 (or greater) or Windows PowerShell 5.1 +- Azure Cli 2.56.0 or greater + +## Azure Service Requirements +The following Azure Service components are required. + +They will be created automatically as part of the deployment, either via [PowerShell](../deploy/deploy.ps1) or [ARM](../deploy/resourcemanager/template.json)) + +- 1 Azure Function app +- 1 Azure Storage Account +- 1 Azure Cosmos DB NoSQL Account +- 2 Azure Key vault minimum +- 1 Azure Event Hub +- 1 Azure Data Explorer Database +- 1 App Service Plan + +*Example Resource Group (Post-Deployment):* + +![](./media/example-azure-resources.png) + +## Permissions + +### Runtime Permissions + +| **Account Needing Permissions** | **Role** | **Minimum Required Scope** | **Automated Assignment Source** | **Reason For Requirement** | | +|---|---|---|---|---|---| +| Kusto Managed Identity | Cosmos DB Account Reader | Cosmos DB Account | [configureKusto.bicep](../deploy/bicep/configureKusto.bicep) | Configuring Kusto Ingestion | [ref](https://learn.microsoft.com/en-us/azure/data-explorer/ingest-data-cosmos-db-connection?tabs=arm&tabpanel_1_arm) | +| | Cosmos DB Data Reader | Cosmos DB "records" container | [configureKusto.bicep](../deploy/bicep/configureKusto.bicep) | Reading data from "records" to ingest | [ref](https://learn.microsoft.com/en-us/azure/data-explorer/ingest-data-cosmos-db-connection?tabs=arm&tabpanel_1_arm) | +| Function App Managed Identity | Storage Account Contributor | Storage Account | [configureKusto.bicep](../deploy/bicep/configureKusto.bicep) | | [ref](https://learn.microsoft.com/en-us/azure/azure-functions/functions-reference?tabs=eventhubs&pivots=programming-language-csharp&connecting-to-host-storage-with-an-identity) | +| | Storage Account Queue Data Contributor | Storage Account | [deployFunction.bicep](../deploy/bicep/deployFunction.bicep) | Queue Trigger | [ref](https://learn.microsoft.com/en-us/azure/azure-functions/functions-reference?tabs=queue&pivots=programming-language-csharp&tabpanel_1_queue) | +| | Storage Account Blob Data Owner | Storage Account | [deployFunction.bicep](../deploy/bicep/deployFunction.bicep) | | [ref](https://learn.microsoft.com/en-us/azure/azure-functions/functions-reference?tabs=eventhubs&pivots=programming-language-csharp&connecting-to-host-storage-with-an-identity) | +| | Event Hubs Data Receiver | Event Hub | [deployFunction.bicep](../deploy/bicep/deployFunction.bicep) | Event Hubs Trigger | [ref](https://learn.microsoft.com/en-us/azure/azure-functions/functions-reference?tabs=eventhubs&pivots=programming-language-csharp&tabpanel_1_eventhubs) | +| | Key Vault Secrets Officer | Key Vault | [deployFunction.bicep](../deploy/bicep/deployFunction.bicep) | Function Secrets | [ref](https://learn.microsoft.com/en-us/azure/azure-functions/functions-reference?tabs=eventhubs&pivots=programming-language-csharp&connecting-to-host-storage-with-an-identity) | +| | Cosmos DB Data Contributor | Cosmos DB Database | [deployFunction.bicep](../deploy/bicep/deployFunction.bicep) | Read/Upsert Processed Data | [ref](https://learn.microsoft.com/en-us/azure/cosmos-db/how-to-setup-rbac#built-in-role-definitions) | +| | CallRecords.Read.All | Microsoft Graph (Tenant) | [deploy.ps1](../deploy/deploy.ps1) | Configure Subscription Retrieve Call Records | [ref](https://learn.microsoft.com/en-us/graph/permissions-reference#callrecordsreadall) | +| Microsoft Graph Change Tracking Service Principal | Key Vault Secrets User | Graph Event Hub Connection String Secret | [deployFunction.bicep](../deploy/bicep/deployFunction.bicep) | Read Event Hub connection string for event publishing | [ref](https://learn.microsoft.com/en-us/graph/change-notifications-delivery-event-hubs#receiving-notifications) | + +### Deployment Permissions + +The recommendation is to grant all of these permissions to a single user account performing the deployment, and to use [deploy.ps1](../deploy/deploy.ps1) + +> [!Note] +> Regarding Multiple Administrator Deployment +> +> This can be done, however, this will result in errors on each run of [deploy.ps1](../deploy/deploy.ps1) where the running account does not have all permissions +> - The parameters passed to [deploy.ps1](../deploy/deploy.ps1) **MUST** be the same for each run, regardless of the admin account +> - When the [deploy.ps1](../deploy/deploy.ps1) script writes an error regarding checking permissions, then the current account does not have the required permissions to continue +> - The step which failed will be noted as the last line before the error +> - So long as the final run of the [deploy.ps1](../deploy/deploy.ps1) script results in no errors, then the application will have deployed successfully + +#### Permissions Required for deploy.ps1 + +> [!Note] +> All Commands tested using Azure Cli version 2.56.0 + +Below is a break down of each underlying Azure Cli command which is used in the script. Each Command has the list of Possible Errors you may see if permissions are not set properly for the currently signed-in user. + +##### Command + +`az account show --query id` + +###### Possible Errors + +- `Failed to connect to subscription '$SubscriptionId'. Please ensure you have access to the subscription and try again.` + +###### API Calls + +- None + +###### Permissions + +- No additional permissions + +##### Command + +`az ad signed-in-user show --query userPrincipalName az ad signed-in-user show --query id` + +###### Possible Errors + +- `Failed to get identity of signed in user! Please ensure you are signed in and try again.` + +###### API Calls + +- GET https://graph.microsoft.com/v1.0/me + +###### Permissions + +- Microsoft Graph Scopes ([ref](https://learn.microsoft.com/en-us/graph/api/user-get#permissions)) + - User.Read + - **OR** + - User.ReadWrite + - **OR** + - User.ReadBasic.All + - **OR** + - User.Read.All + - **OR** + - User.ReadWrite.All + - **OR** + - Directory.Read.All + - **OR** + - Directory.ReadWrite.All + +##### Command + +`az account show --query tenantId` + +###### Possible Errors + +- `Failed to get tenant id for subscription '$SubscriptionId'. Please ensure you have access to the subscription and try again.` + +###### API Calls + +- None + +###### Permissions + +- Must Be User in Tenant associated with Subscription +- No additional permissions + +##### Command + +`az ad sp list --spn $APP_ID --query "[].id"` + +###### Possible Errors + +- `Failed to get the SPN object id for the Microsoft Graph Change Tracking app. Please ensure you have access to the tenant and try again.` + +- `Failed to get the SPN object id for Microsoft Graph. Please ensure you have access to the tenant and try again.` + +###### API Calls + +- GET https://graph.microsoft.com/v1.0/servicePrincipals?$filter=servicePrincipalNames/any(c:c/id+eq+'$APP_ID') + +###### Permissions + +- Microsoft Graph Scopes ([ref](https://learn.microsoft.com/en-us/graph/api/serviceprincipal-list#permissions)) + - Application.Read.All + - **OR** + - Application.ReadWrite.All + - **OR** + - Directory.Read.All + - **OR** + - Directory.ReadWrite.All + +##### Command + +`az group show --name $RESOURCE_GROUP` + +###### Possible Errors + +- `Failed to create resource group '$ResourceGroupName' in location '$Location'. Please ensure you have access to the subscription and try again.` + +###### API Calls + +- GET https://management.azure.com/subscriptions/$SUBSCRIPTION_ID/resourcegroups/$RESOURCE_GROUP?api-version=2022-09-01 + +###### Permissions + +- Azure RBAC Roles + - Microsoft.Resources/subscriptions/resourceGroups/read + +##### Command + +`az group create --name $RESOURCE_GROUP --location $LOCATION` + +###### Possible Errors + +- `Failed to create resource group '$ResourceGroupName' in location '$Location'. Please ensure you have access to the subscription and try again.` + +###### API Calls + +- PUT https://management.azure.com/subscriptions/$SUBSCRIPTION_ID/resourcegroups/$RESOURCE_GROUP?api-version=2022-09-01 + +###### Permissions + +- Azure RBAC Roles + - Microsoft.Resources/subscriptions/resourceGroups/read + - **AND** + - Microsoft.Resources/subscriptions/resourceGroups/write + +##### Command + +`az rest --method get --url "https://graph.microsoft.com/v1.0/servicePrincipals/$SPN_ID/appRoleAssignments"` + +###### Possible Errors + +- `Failed to add app role '$perm' to Service Principal '$appPrincipalprincipalId'. Please ensure you have access to the tenant and try again.` + +###### API Calls + +- GET https://graph.microsoft.com/v1.0/servicePrincipals/$SPN_ID/appRoleAssignments + +###### Permissions + +- Microsoft Graph Scopes ([ref](https://learn.microsoft.com/en-us/graph/api/serviceprincipal-list-approleassignments#permissions)) + - Application.Read.All + - **OR** + - Application.ReadWrite.All + - **OR** + - Directory.Read.All + - **OR** + - Directory.ReadWrite.All + +##### Command + +`az rest --method post --url "https://graph.microsoft.com/v1.0/servicePrincipals/$SPN_ID/appRoleAssignments" --body "$body"` + +###### Possible Errors + +- `Failed to add app role '$perm' to Service Principal '$appPrincipalprincipalId'. Please ensure you have access to the tenant and try again.` + +###### API Calls + +- POST https://graph.microsoft.com/v1.0/servicePrincipals/$SPN_ID/appRoleAssignments + +###### Permissions + +- Microsoft Graph Scopes ([ref](https://learn.microsoft.com/en-us/graph/api/serviceprincipal-post-approleassignments#permissions)) + - AppRoleAssignment.ReadWrite.All + - **AND** + - Application.Read.All + - **OR** + - Directory.Read.All + +##### Command + +`az webapp log deployment show --resource-group $RESOURCE_GROUP --name $FUNCTION_APP` + +###### Possible Errors + +- `Failed to get deployment logs for function app '$functionName'. Please ensure you have access to the subscription and try again.` + +###### API Calls + +- GET https://management.azure.com/subscriptions/$SUBSCRIPTION_ID/resourceGroups/$RESOURCE_GROUP/providers/Microsoft.Web/sites/$FUNCTION_APP?api-version=2023-01-01 +- GET https://management.azure.com/subscriptions/$SUBSCRIPTION_ID/resourceGroups/$RESOURCE_GROUP/providers/Microsoft.Web/sites/$FUNCTION_APP/basicPublishingCredentialsPolicies/scm?api-version=2023-01-01 +- POST https://management.azure.com/subscriptions/$SUBSCRIPTION_ID/resourceGroups/$RESOURCE_GROUP/providers/Microsoft.Web/sites/$FUNCTION_APP/config/publishingcredentials/list?api-version=2023-01-01 + +###### Permissions + +- Azure RBAC Roles + - Microsoft.Web/sites/Read + - **AND** + - Microsoft.Web/sites/basicPublishingCredentialsPolicies/scm/Read + - **AND** + - Microsoft.Web/sites/config/list/Action + +##### Command + +`az functionapp keys list --resource-group $RESOURCE_GROUP --name $FUNCTION_APP --query masterKey` + +###### Possible Errors + +- `Failed to get master key for function app '$functionName'.` + +###### API Calls + +- POST https://management.azure.com/subscriptions/$SUBSCRIPTION_ID/resourceGroups/$RESOURCE_GROUP/providers/Microsoft.Web/sites/$FUNCTION_APP/host/default/listkeys?api-version=2023-01-01 + +###### Permissions + +- Azure RBAC Roles + - Microsoft.Web/sites/host/listkeys/action + +##### Command + +`az deployment group show --resource-group $RESOURCE_GROUP --name $DEPLOYMENT_NAME --query properties` + +###### Possible Errors + +- `Could not get $DeploymentType deployment in resource group '$ResourceGroupName'. Please ensure you have access to the subscription and try again.` +- `Failed to create $DeploymentType in resource group '$ResourceGroupName'. Please ensure you have access to the subscription and try again.` + +###### API Calls + +- GET https://management.azure.com/subscriptions/$SUBSCRIPTION_ID/resourcegroups/$RESOURCE_GROUP/providers/Microsoft.Resources/deployments/$DEPLOYMENT_NAME?api-version=2022-09-01 + +###### Permissions + +- Azure RBAC Roles + - Microsoft.Resources/deployments/read + +##### Command + +`az deployment group create --resource-group $RESOURCE_GROUP --name $DEPLOYMENT_NAME --mode Incremental --template-file $TemplateFile --no-prompt true --no-wait --query properties --parameters ...` + +###### Possible Errors + +- `Failed to create $DeploymentType in resource group '$ResourceGroupName'. Please ensure you have access to the subscription and try again.` + +###### API Calls + +- POST https://management.azure.com/subscriptions/$SUBSCRIPTION_ID/resourcegroups/$RESOURCE_GROUP/providers/Microsoft.Resources/deployments/$DEPLOYMENT_NAME?api-version=2022-09-01 + +###### Permissions + +- Azure RBAC Roles + - Microsoft.Resources/deployments/write + +##### Command + +`az deployment operation group list --resource-group $RESOURCE_GROUP --name $DEPLOYMENT_NAME --query "[].{provisioningState:properties.provisioningState,targetResource:properties.targetResource.id,statusMessage:properties.statusMessage.error.message}"` + +###### Possible Errors + +- `Failed to create $DeploymentType in resource group '$ResourceGroupName'. Please ensure you have access to the subscription and try again.` + +###### API Calls + +- GET https://management.azure.com/subscriptions/$SUBSCRIPTION_ID/resourcegroups/$RESOURCE_GROUP/providers/Microsoft.Resources/deployments/$DEPLOYMENT_NAME/operations?api-version=2022-09-01 + +###### Permissions + +- Azure RBAC Roles + - Microsoft.Resources/deployments/operations/read + +#### Permissions for Resource Deployment + +> [!Note] +> Each role requires at least resource group level scoped assignment + +> [!Note] +> These roles are required whether deploying via [deploy.ps1](../deploy/deploy.ps1) **OR** [ARM](../deploy/resourcemanager/template.json) + +| **Bicep Template** | **Azure RBAC Roles** | +|---|---| +| [deployKusto.bicep](../deploy/bicep/deployKusto.bicep) | Microsoft.Kusto/clusters/read
Microsoft.Kusto/clusters/create
Microsoft.Kusto/clusters/databases/create | +| [deployCosmos.bicep](../deploy/bicep/deployCosmos.bicep) | Microsoft.DocumentDB/databaseAccounts/create
Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers/create
Microsoft.DocumentDB/databaseAccounts/sqlDatabases/create | +| [deployFunction.bicep](../deploy/bicep/deployFunction.bicep) | Microsoft.DocumentDB/databaseAccounts/read
Microsoft.DocumentDB/databaseAccounts/sqlDatabases/read
Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers/read
Microsoft.EventHub/namespaces/read
Microsoft.KeyVault/vaults/read
Microsoft.KeyVault/vaults/secrets/read
Microsoft.Storage/storageAccounts/read
Microsoft.Web/sites/read
Microsoft.Authorization/roleAssignments/create
Microsoft.DocumentDB/databaseAccounts/sqlRoleAssignments/create
Microsoft.EventHub/namespaces/create
Microsoft.EventHub/namespaces/eventhubs/authorizationRules/action
Microsoft.EventHub/namespaces/eventhubs/authorizationRules/create
Microsoft.EventHub/namespaces/eventhubs/create
Microsoft.KeyVault/vaults/create
Microsoft.KeyVault/vaults/secrets/create
Microsoft.Storage/storageAccounts/action
Microsoft.Storage/storageAccounts/create
Microsoft.Storage/storageAccounts/queueServices/create
Microsoft.Storage/storageAccounts/queueServices/queues/create
Microsoft.Web/serverfarms/create
Microsoft.Web/sites/config/create
Microsoft.Web/sites/create | diff --git a/docs/troubleshooting.md b/docs/troubleshooting.md new file mode 100644 index 0000000..0dafa26 --- /dev/null +++ b/docs/troubleshooting.md @@ -0,0 +1,26 @@ +# Troubleshooting + +## Deployment + +### Error - No SPN for Graph Change Tracking +The required Service Principal for the First Party Application 'Microsoft Graph Change Tracking' does not exist in the tenant where Call Record Insights is deployed + +[More Information](https://learn.microsoft.com/en-us/graph/change-notifications-delivery-event-hubs#what-if-the-microsoft-graph-change-tracking-application-is-missing) + +#### Resolution +Register the Service Principal for the First Party Application in the tenant where Call Record Insights is deployed + +*Example*: +```powershell +Connect-MgGraph -Scopes 'Application.ReadWrite.All' +$GraphChangeTrackingAppId = '0bf30f3b-4a52-48df-9a82-234910c4a086' +$Existing = Get-MgServicePrincipal -Filter "appId eq '$GraphChangeTrackingAppId'" -ErrorAction SilentlyContinue +if (!$Existing) { + Write-Warning "SPN not found, creating new..." + New-MgServicePrincipal -AppId \$GraphChangeTrackingAppId +} +else { + Write-Information "SPN already created..." + $Existing +} +``` diff --git a/src/.editorconfig b/src/.editorconfig new file mode 100644 index 0000000..f6e09a5 --- /dev/null +++ b/src/.editorconfig @@ -0,0 +1,1091 @@ +# NOTE: Requires **VS2019 16.3** or later + +# Microsoft SDL Roslyn Rules - Required and Recommended (Error) v9.4 +# Description: This rule set contains all Microsoft SDL required and recommended rules for Microsoft.CodeAnalysis.NetAnalyzers v8.0.0-preview.23420.2 (and Microsoft.CodeAnalysis.FxCopAnalyzers) and Microsoft.Internal.Analyzers v2.9.8, configured to error rather than warn. Generated 2023-09-27T00:50:42Z. + +# Code files +[*.{cs,vb}] + + +dotnet_diagnostic.Async001.severity = none + +dotnet_diagnostic.Async002.severity = none + +dotnet_diagnostic.Async003.severity = none + +dotnet_diagnostic.Async004.severity = none + +dotnet_diagnostic.Async005.severity = none + +dotnet_diagnostic.Async006.severity = none + +# Do not declare static members on generic types +dotnet_diagnostic.CA1000.severity = none + +# Types that own disposable fields should be disposable +dotnet_diagnostic.CA1001.severity = none + +# Do not expose generic lists +dotnet_diagnostic.CA1002.severity = none + +# Use generic event handler instances +dotnet_diagnostic.CA1003.severity = none + +# Avoid excessive parameters on generic types +dotnet_diagnostic.CA1005.severity = none + +# Enums should have zero value +dotnet_diagnostic.CA1008.severity = none + +# Generic interface should also be implemented +dotnet_diagnostic.CA1010.severity = none + +# Abstract types should not have public constructors +dotnet_diagnostic.CA1012.severity = none + +# Mark assemblies with CLSCompliant +dotnet_diagnostic.CA1014.severity = none + +# Mark assemblies with assembly version +dotnet_diagnostic.CA1016.severity = none + +# Mark assemblies with ComVisible +dotnet_diagnostic.CA1017.severity = none + +# Mark attributes with AttributeUsageAttribute +dotnet_diagnostic.CA1018.severity = none + +# Define accessors for attribute arguments +dotnet_diagnostic.CA1019.severity = none + +# Avoid out parameters +dotnet_diagnostic.CA1021.severity = none + +# Use properties where appropriate +dotnet_diagnostic.CA1024.severity = none + +# Mark enums with FlagsAttribute +dotnet_diagnostic.CA1027.severity = none + +# Enum Storage should be Int32 +dotnet_diagnostic.CA1028.severity = none + +# Use events where appropriate +dotnet_diagnostic.CA1030.severity = none + +# Do not catch general exception types +dotnet_diagnostic.CA1031.severity = none + +# Implement standard exception constructors +dotnet_diagnostic.CA1032.severity = none + +# Interface methods should be callable by child types +dotnet_diagnostic.CA1033.severity = none + +# Nested types should not be visible +dotnet_diagnostic.CA1034.severity = none + +# Override methods on comparable types +dotnet_diagnostic.CA1036.severity = none + +# Avoid empty interfaces +dotnet_diagnostic.CA1040.severity = none + +# Provide ObsoleteAttribute message +dotnet_diagnostic.CA1041.severity = none + +# Use Integral Or String Argument For Indexers +dotnet_diagnostic.CA1043.severity = none + +# Properties should not be write only +dotnet_diagnostic.CA1044.severity = none + +# Do not pass types by reference +dotnet_diagnostic.CA1045.severity = none + +# Do not overload equality operator on reference types +dotnet_diagnostic.CA1046.severity = none + +# Do not declare protected member in sealed type +dotnet_diagnostic.CA1047.severity = none + +# Declare types in namespaces +dotnet_diagnostic.CA1050.severity = none + +# Do not declare visible instance fields +dotnet_diagnostic.CA1051.severity = none + +# Static holder types should be Static or NotInheritable +dotnet_diagnostic.CA1052.severity = none + +# URI-like parameters should not be strings +dotnet_diagnostic.CA1054.severity = none + +# URI-like return values should not be strings +dotnet_diagnostic.CA1055.severity = none + +# URI-like properties should not be strings +dotnet_diagnostic.CA1056.severity = none + +# Types should not extend certain base types +dotnet_diagnostic.CA1058.severity = none + +# Move pinvokes to native methods class +dotnet_diagnostic.CA1060.severity = none + +# Do not hide base class methods +dotnet_diagnostic.CA1061.severity = none + +# Validate arguments of public methods +dotnet_diagnostic.CA1062.severity = none + +# Implement IDisposable Correctly +dotnet_diagnostic.CA1063.severity = none + +# Exceptions should be public +dotnet_diagnostic.CA1064.severity = none + +# Do not raise exceptions in unexpected locations +dotnet_diagnostic.CA1065.severity = none + +# Implement IEquatable when overriding Object.Equals +dotnet_diagnostic.CA1066.severity = none + +# Override Object.Equals(object) when implementing IEquatable<T> +dotnet_diagnostic.CA1067.severity = none + +# CancellationToken parameters must come last +dotnet_diagnostic.CA1068.severity = none + +# Enums values should not be duplicated +dotnet_diagnostic.CA1069.severity = none + +# Do not declare event fields as virtual +dotnet_diagnostic.CA1070.severity = none + +# Avoid using cref tags with a prefix +dotnet_diagnostic.CA1200.severity = none + +# Do not pass literals as localized parameters +dotnet_diagnostic.CA1303.severity = none + +# Specify CultureInfo +dotnet_diagnostic.CA1304.severity = none + +# Specify IFormatProvider +dotnet_diagnostic.CA1305.severity = none + +# Specify StringComparison for clarity +dotnet_diagnostic.CA1307.severity = none + +# Normalize strings to uppercase +dotnet_diagnostic.CA1308.severity = none + +# Use ordinal string comparison +dotnet_diagnostic.CA1309.severity = none + +# Specify StringComparison for correctness +dotnet_diagnostic.CA1310.severity = none + +# Specify a culture or use an invariant version +dotnet_diagnostic.CA1311.severity = none + +# P/Invokes should not be visible +dotnet_diagnostic.CA1401.severity = none + +# Validate platform compatibility +dotnet_diagnostic.CA1416.severity = none + +# Do not use 'OutAttribute' on string parameters for P/Invokes +dotnet_diagnostic.CA1417.severity = none + +# Use valid platform string +dotnet_diagnostic.CA1418.severity = none + +# Provide a parameterless constructor that is as visible as the containing type for concrete types derived from 'System.Runtime.InteropServices.SafeHandle' +dotnet_diagnostic.CA1419.severity = none + +# Property, type, or attribute requires runtime marshalling +dotnet_diagnostic.CA1420.severity = none + +# This method uses runtime marshalling even when the 'DisableRuntimeMarshallingAttribute' is applied +dotnet_diagnostic.CA1421.severity = none + +# Validate platform compatibility +dotnet_diagnostic.CA1422.severity = none + +# Avoid excessive inheritance +dotnet_diagnostic.CA1501.severity = none + +# Avoid excessive complexity +dotnet_diagnostic.CA1502.severity = none + +# Avoid unmaintainable code +dotnet_diagnostic.CA1505.severity = none + +# Avoid excessive class coupling +dotnet_diagnostic.CA1506.severity = none + +# Use nameof to express symbol names +dotnet_diagnostic.CA1507.severity = none + +# Avoid dead conditional code +dotnet_diagnostic.CA1508.severity = none + +# Invalid entry in code metrics rule specification file +dotnet_diagnostic.CA1509.severity = none + +# Use ArgumentNullException throw helper +dotnet_diagnostic.CA1510.severity = none + +# Use ArgumentException throw helper +dotnet_diagnostic.CA1511.severity = none + +# Use ArgumentOutOfRangeException throw helper +dotnet_diagnostic.CA1512.severity = none + +# Use ObjectDisposedException throw helper +dotnet_diagnostic.CA1513.severity = none + +# Do not name enum values 'Reserved' +dotnet_diagnostic.CA1700.severity = none + +# Identifiers should not contain underscores +dotnet_diagnostic.CA1707.severity = none + +# Identifiers should differ by more than case +dotnet_diagnostic.CA1708.severity = none + +# Identifiers should have correct suffix +dotnet_diagnostic.CA1710.severity = none + +# Identifiers should not have incorrect suffix +dotnet_diagnostic.CA1711.severity = none + +# Do not prefix enum values with type name +dotnet_diagnostic.CA1712.severity = none + +# Events should not have 'Before' or 'After' prefix +dotnet_diagnostic.CA1713.severity = none + +dotnet_diagnostic.CA1714.severity = none + +# Identifiers should have correct prefix +dotnet_diagnostic.CA1715.severity = none + +# Identifiers should not match keywords +dotnet_diagnostic.CA1716.severity = none + +dotnet_diagnostic.CA1717.severity = none + +# Identifier contains type name +dotnet_diagnostic.CA1720.severity = none + +# Property names should not match get methods +dotnet_diagnostic.CA1721.severity = none + +# Type names should not match namespaces +dotnet_diagnostic.CA1724.severity = none + +# Parameter names should match base declaration +dotnet_diagnostic.CA1725.severity = none + +# Use PascalCase for named placeholders +dotnet_diagnostic.CA1727.severity = none + +dotnet_diagnostic.CA1801.severity = none + +# Use literals where appropriate +dotnet_diagnostic.CA1802.severity = none + +# Do not initialize unnecessarily +dotnet_diagnostic.CA1805.severity = none + +# Do not ignore method results +dotnet_diagnostic.CA1806.severity = none + +# Initialize reference type static fields inline +dotnet_diagnostic.CA1810.severity = none + +# Avoid uninstantiated internal classes +dotnet_diagnostic.CA1812.severity = none + +# Avoid unsealed attributes +dotnet_diagnostic.CA1813.severity = none + +# Prefer jagged arrays over multidimensional +dotnet_diagnostic.CA1814.severity = none + +# Override equals and operator equals on value types +dotnet_diagnostic.CA1815.severity = none + +# Dispose methods should call SuppressFinalize +dotnet_diagnostic.CA1816.severity = none + +# Properties should not return arrays +dotnet_diagnostic.CA1819.severity = none + +# Test for empty strings using string length +dotnet_diagnostic.CA1820.severity = none + +# Remove empty Finalizers +dotnet_diagnostic.CA1821.severity = none + +# Mark members as static +dotnet_diagnostic.CA1822.severity = none + +# Avoid unused private fields +dotnet_diagnostic.CA1823.severity = none + +# Mark assemblies with NeutralResourcesLanguageAttribute +dotnet_diagnostic.CA1824.severity = none + +# Avoid zero-length array allocations +dotnet_diagnostic.CA1825.severity = none + +# Do not use Enumerable methods on indexable collections +dotnet_diagnostic.CA1826.severity = none + +# Do not use Count() or LongCount() when Any() can be used +dotnet_diagnostic.CA1827.severity = none + +# Do not use CountAsync() or LongCountAsync() when AnyAsync() can be used +dotnet_diagnostic.CA1828.severity = none + +# Use Length/Count property instead of Count() when available +dotnet_diagnostic.CA1829.severity = none + +# Prefer strongly-typed Append and Insert method overloads on StringBuilder +dotnet_diagnostic.CA1830.severity = none + +# Use AsSpan or AsMemory instead of Range-based indexers when appropriate +dotnet_diagnostic.CA1831.severity = none + +# Use AsSpan or AsMemory instead of Range-based indexers when appropriate +dotnet_diagnostic.CA1832.severity = none + +# Use AsSpan or AsMemory instead of Range-based indexers when appropriate +dotnet_diagnostic.CA1833.severity = none + +# Consider using 'StringBuilder.Append(char)' when applicable +dotnet_diagnostic.CA1834.severity = none + +# Prefer the 'Memory'-based overloads for 'ReadAsync' and 'WriteAsync' +dotnet_diagnostic.CA1835.severity = none + +# Prefer IsEmpty over Count +dotnet_diagnostic.CA1836.severity = none + +# Use 'Environment.ProcessId' +dotnet_diagnostic.CA1837.severity = none + +# Avoid 'StringBuilder' parameters for P/Invokes +dotnet_diagnostic.CA1838.severity = none + +# Use 'Environment.ProcessPath' +dotnet_diagnostic.CA1839.severity = none + +# Use 'Environment.CurrentManagedThreadId' +dotnet_diagnostic.CA1840.severity = none + +# Prefer Dictionary.Contains methods +dotnet_diagnostic.CA1841.severity = none + +# Do not use 'WhenAll' with a single task +dotnet_diagnostic.CA1842.severity = none + +# Do not use 'WaitAll' with a single task +dotnet_diagnostic.CA1843.severity = none + +# Provide memory-based overrides of async methods when subclassing 'Stream' +dotnet_diagnostic.CA1844.severity = none + +# Use span-based 'string.Concat' +dotnet_diagnostic.CA1845.severity = none + +# Prefer 'AsSpan' over 'Substring' +dotnet_diagnostic.CA1846.severity = none + +# Use char literal for a single character lookup +dotnet_diagnostic.CA1847.severity = none + +# Use the LoggerMessage delegates +dotnet_diagnostic.CA1848.severity = none + +# Call async methods when in an async method +dotnet_diagnostic.CA1849.severity = none + +# Prefer static 'HashData' method over 'ComputeHash' +dotnet_diagnostic.CA1850.severity = none + +# Possible multiple enumerations of 'IEnumerable' collection +dotnet_diagnostic.CA1851.severity = none + +# Seal internal types +dotnet_diagnostic.CA1852.severity = none + +# Unnecessary call to 'Dictionary.ContainsKey(key)' +dotnet_diagnostic.CA1853.severity = none + +# Prefer the 'IDictionary.TryGetValue(TKey, out TValue)' method +dotnet_diagnostic.CA1854.severity = none + +# Prefer 'Clear' over 'Fill' +dotnet_diagnostic.CA1855.severity = none + +# Incorrect usage of ConstantExpected attribute +dotnet_diagnostic.CA1856.severity = none + +# A constant is expected for the parameter +dotnet_diagnostic.CA1857.severity = none + +# Use 'StartsWith' instead of 'IndexOf' +dotnet_diagnostic.CA1858.severity = none + +# Use concrete types when possible for improved performance +dotnet_diagnostic.CA1859.severity = none + +# Avoid using 'Enumerable.Any()' extension method +dotnet_diagnostic.CA1860.severity = none + +# Avoid constant arrays as arguments +dotnet_diagnostic.CA1861.severity = none + +# Prefer the 'StringComparison' method overloads to perform case-insensitive string comparisons +dotnet_diagnostic.CA1862.severity = none + +# Use 'CompositeFormat' +dotnet_diagnostic.CA1863.severity = none + +# Prefer the 'IDictionary.TryAdd(TKey, TValue)' method +dotnet_diagnostic.CA1864.severity = none + +# Use char overload +dotnet_diagnostic.CA1865.severity = none + +# Use char overload +dotnet_diagnostic.CA1866.severity = none + +# Use char overload +dotnet_diagnostic.CA1867.severity = none + +# Unnecessary call to 'Contains(item)' +dotnet_diagnostic.CA1868.severity = none + +# Cache and reuse 'JsonSerializerOptions' instances +dotnet_diagnostic.CA1869.severity = none + +# Dispose objects before losing scope +dotnet_diagnostic.CA2000.severity = none + +# Do not lock on objects with weak identity +dotnet_diagnostic.CA2002.severity = none + +# Consider calling ConfigureAwait on the awaited task +dotnet_diagnostic.CA2007.severity = none + +# Do not create tasks without passing a TaskScheduler +dotnet_diagnostic.CA2008.severity = none + +# Do not call ToImmutableCollection on an ImmutableCollection value +dotnet_diagnostic.CA2009.severity = none + +dotnet_diagnostic.CA2010.severity = none + +# Avoid infinite recursion +dotnet_diagnostic.CA2011.severity = none + +# Use ValueTasks correctly +dotnet_diagnostic.CA2012.severity = none + +# Do not use ReferenceEquals with value types +dotnet_diagnostic.CA2013.severity = none + +# Do not use stackalloc in loops +dotnet_diagnostic.CA2014.severity = none + +# Do not define finalizers for types derived from MemoryManager<T> +dotnet_diagnostic.CA2015.severity = none + +# Forward the 'CancellationToken' parameter to methods +dotnet_diagnostic.CA2016.severity = none + +# Parameter count mismatch +dotnet_diagnostic.CA2017.severity = none + +# 'Buffer.BlockCopy' expects the number of bytes to be copied for the 'count' argument +dotnet_diagnostic.CA2018.severity = none + +# Improper 'ThreadStatic' field initialization +dotnet_diagnostic.CA2019.severity = none + +# Prevent behavioral change +dotnet_diagnostic.CA2020.severity = none + +# Do not call Enumerable.Cast<T> or Enumerable.OfType<T> with incompatible types +dotnet_diagnostic.CA2021.severity = none + +# Review SQL queries for security vulnerabilities +dotnet_diagnostic.CA2100.severity = none + +# Specify marshaling for P/Invoke string arguments +dotnet_diagnostic.CA2101.severity = none + +dotnet_diagnostic.CA2109.severity = none + +# Seal methods that satisfy private interfaces +dotnet_diagnostic.CA2119.severity = none + +# Do Not Catch Corrupted State Exceptions +dotnet_diagnostic.CA2153.severity = error + +# Rethrow to preserve stack details +dotnet_diagnostic.CA2200.severity = none + +# Do not raise reserved exception types +dotnet_diagnostic.CA2201.severity = none + +# Initialize value type static fields inline +dotnet_diagnostic.CA2207.severity = none + +# Instantiate argument exceptions correctly +dotnet_diagnostic.CA2208.severity = none + +# Non-constant fields should not be visible +dotnet_diagnostic.CA2211.severity = none + +# Disposable fields should be disposed +dotnet_diagnostic.CA2213.severity = none + +# Do not call overridable methods in constructors +dotnet_diagnostic.CA2214.severity = none + +# Dispose methods should call base class dispose +dotnet_diagnostic.CA2215.severity = none + +# Disposable types should declare finalizer +dotnet_diagnostic.CA2216.severity = none + +# Do not mark enums with FlagsAttribute +dotnet_diagnostic.CA2217.severity = none + +# Override GetHashCode on overriding Equals +dotnet_diagnostic.CA2218.severity = none + +# Do not raise exceptions in finally clauses +dotnet_diagnostic.CA2219.severity = none + +# Override Equals on overloading operator equals +dotnet_diagnostic.CA2224.severity = none + +# Operator overloads have named alternates +dotnet_diagnostic.CA2225.severity = none + +# Operators should have symmetrical overloads +dotnet_diagnostic.CA2226.severity = none + +# Collection properties should be read only +dotnet_diagnostic.CA2227.severity = none + +# Implement serialization constructors +dotnet_diagnostic.CA2229.severity = none + +# Overload operator equals on overriding value type Equals +dotnet_diagnostic.CA2231.severity = none + +# Pass system uri objects instead of strings +dotnet_diagnostic.CA2234.severity = none + +# Mark all non-serializable fields +dotnet_diagnostic.CA2235.severity = none + +# Mark ISerializable types with serializable +dotnet_diagnostic.CA2237.severity = none + +# Provide correct arguments to formatting methods +dotnet_diagnostic.CA2241.severity = none + +# Test for NaN correctly +dotnet_diagnostic.CA2242.severity = none + +# Attribute string literals should parse correctly +dotnet_diagnostic.CA2243.severity = none + +# Do not duplicate indexed element initializations +dotnet_diagnostic.CA2244.severity = none + +# Do not assign a property to itself +dotnet_diagnostic.CA2245.severity = none + +# Assigning symbol and its member in the same statement +dotnet_diagnostic.CA2246.severity = none + +# Argument passed to TaskCompletionSource constructor should be TaskCreationOptions enum instead of TaskContinuationOptions enum +dotnet_diagnostic.CA2247.severity = none + +# Provide correct 'enum' argument to 'Enum.HasFlag' +dotnet_diagnostic.CA2248.severity = none + +# Consider using 'string.Contains' instead of 'string.IndexOf' +dotnet_diagnostic.CA2249.severity = none + +# Use 'ThrowIfCancellationRequested' +dotnet_diagnostic.CA2250.severity = none + +# Use 'string.Equals' +dotnet_diagnostic.CA2251.severity = none + +# This API requires opting into preview features +dotnet_diagnostic.CA2252.severity = none + +# Named placeholders should not be numeric values +dotnet_diagnostic.CA2253.severity = none + +# Template should be a static expression +dotnet_diagnostic.CA2254.severity = none + +# The 'ModuleInitializer' attribute should not be used in libraries +dotnet_diagnostic.CA2255.severity = none + +# All members declared in parent interfaces must have an implementation in a DynamicInterfaceCastableImplementation-attributed interface +dotnet_diagnostic.CA2256.severity = none + +# Members defined on an interface with the 'DynamicInterfaceCastableImplementationAttribute' should be 'static' +dotnet_diagnostic.CA2257.severity = none + +# Providing a 'DynamicInterfaceCastableImplementation' interface in Visual Basic is unsupported +dotnet_diagnostic.CA2258.severity = none + +# 'ThreadStatic' only affects static fields +dotnet_diagnostic.CA2259.severity = none + +# Use correct type parameter +dotnet_diagnostic.CA2260.severity = none + +# Do not use ConfigureAwaitOptions.SuppressThrowing with Task<TResult> +dotnet_diagnostic.CA2261.severity = none + +# Do not use insecure deserializer BinaryFormatter +dotnet_diagnostic.CA2300.severity = suggestion + +# Do not call BinaryFormatter.Deserialize without first setting BinaryFormatter.Binder +dotnet_diagnostic.CA2301.severity = error + +# Ensure BinaryFormatter.Binder is set before calling BinaryFormatter.Deserialize +dotnet_diagnostic.CA2302.severity = error + +# Do not use insecure deserializer LosFormatter +dotnet_diagnostic.CA2305.severity = error + +# Do not use insecure deserializer NetDataContractSerializer +dotnet_diagnostic.CA2310.severity = suggestion + +# Do not deserialize without first setting NetDataContractSerializer.Binder +dotnet_diagnostic.CA2311.severity = error + +# Ensure NetDataContractSerializer.Binder is set before deserializing +dotnet_diagnostic.CA2312.severity = error + +# Do not use insecure deserializer ObjectStateFormatter +dotnet_diagnostic.CA2315.severity = error + +# Do not deserialize with JavaScriptSerializer using a SimpleTypeResolver +dotnet_diagnostic.CA2321.severity = error + +# Ensure JavaScriptSerializer is not initialized with SimpleTypeResolver before deserializing +dotnet_diagnostic.CA2322.severity = suggestion + +# Do not use TypeNameHandling values other than None +dotnet_diagnostic.CA2326.severity = none + +# Do not use insecure JsonSerializerSettings +dotnet_diagnostic.CA2327.severity = error + +# Ensure that JsonSerializerSettings are secure +dotnet_diagnostic.CA2328.severity = error + +# Do not deserialize with JsonSerializer using an insecure configuration +dotnet_diagnostic.CA2329.severity = error + +# Ensure that JsonSerializer has a secure configuration when deserializing +dotnet_diagnostic.CA2330.severity = error + +# Do not use DataTable.ReadXml() with untrusted data +dotnet_diagnostic.CA2350.severity = suggestion + +# Do not use DataSet.ReadXml() with untrusted data +dotnet_diagnostic.CA2351.severity = suggestion + +# Unsafe DataSet or DataTable in serializable type can be vulnerable to remote code execution attacks +dotnet_diagnostic.CA2352.severity = suggestion + +# Unsafe DataSet or DataTable in serializable type +dotnet_diagnostic.CA2353.severity = suggestion + +# Unsafe DataSet or DataTable in deserialized object graph can be vulnerable to remote code execution attacks +dotnet_diagnostic.CA2354.severity = suggestion + +# Unsafe DataSet or DataTable type found in deserializable object graph +dotnet_diagnostic.CA2355.severity = suggestion + +# Unsafe DataSet or DataTable type in web deserializable object graph +dotnet_diagnostic.CA2356.severity = suggestion + +# Ensure auto-generated class containing DataSet.ReadXml() is not used with untrusted data +dotnet_diagnostic.CA2361.severity = suggestion + +# Unsafe DataSet or DataTable in auto-generated serializable type can be vulnerable to remote code execution attacks +dotnet_diagnostic.CA2362.severity = suggestion + +# Review code for SQL injection vulnerabilities +dotnet_diagnostic.CA3001.severity = none + +# Review code for XSS vulnerabilities +dotnet_diagnostic.CA3002.severity = none + +# Review code for file path injection vulnerabilities +dotnet_diagnostic.CA3003.severity = none + +# Review code for information disclosure vulnerabilities +dotnet_diagnostic.CA3004.severity = none + +# Review code for LDAP injection vulnerabilities +dotnet_diagnostic.CA3005.severity = none + +# Review code for process command injection vulnerabilities +dotnet_diagnostic.CA3006.severity = none + +# Review code for open redirect vulnerabilities +dotnet_diagnostic.CA3007.severity = none + +# Review code for XPath injection vulnerabilities +dotnet_diagnostic.CA3008.severity = none + +# Review code for XML injection vulnerabilities +dotnet_diagnostic.CA3009.severity = none + +# Review code for XAML injection vulnerabilities +dotnet_diagnostic.CA3010.severity = none + +# Review code for DLL injection vulnerabilities +dotnet_diagnostic.CA3011.severity = none + +# Review code for regex injection vulnerabilities +dotnet_diagnostic.CA3012.severity = none + +# Do Not Add Schema By URL +dotnet_diagnostic.CA3061.severity = error + +# Insecure DTD processing in XML +dotnet_diagnostic.CA3075.severity = error + +# Insecure XSLT script processing +dotnet_diagnostic.CA3076.severity = error + +# Insecure Processing in API Design, XmlDocument and XmlTextReader +dotnet_diagnostic.CA3077.severity = error + +# Mark Verb Handlers With Validate Antiforgery Token +dotnet_diagnostic.CA3147.severity = error + +# Do Not Use Weak Cryptographic Algorithms +dotnet_diagnostic.CA5350.severity = error + +# Do Not Use Broken Cryptographic Algorithms +dotnet_diagnostic.CA5351.severity = error + +# Review cipher mode usage with cryptography experts +dotnet_diagnostic.CA5358.severity = error + +# Do Not Disable Certificate Validation +dotnet_diagnostic.CA5359.severity = suggestion + +# Do Not Call Dangerous Methods In Deserialization +dotnet_diagnostic.CA5360.severity = none + +# Do Not Disable SChannel Use of Strong Crypto +dotnet_diagnostic.CA5361.severity = error + +# Potential reference cycle in deserialized object graph +dotnet_diagnostic.CA5362.severity = none + +# Do Not Disable Request Validation +dotnet_diagnostic.CA5363.severity = none + +# Do Not Use Deprecated Security Protocols +dotnet_diagnostic.CA5364.severity = error + +# Do Not Disable HTTP Header Checking +dotnet_diagnostic.CA5365.severity = none + +# Use XmlReader for 'DataSet.ReadXml()' +dotnet_diagnostic.CA5366.severity = suggestion + +# Do Not Serialize Types With Pointer Fields +dotnet_diagnostic.CA5367.severity = none + +# Set ViewStateUserKey For Classes Derived From Page +dotnet_diagnostic.CA5368.severity = none + +# Use XmlReader for 'XmlSerializer.Deserialize()' +dotnet_diagnostic.CA5369.severity = suggestion + +# Use XmlReader for XmlValidatingReader constructor +dotnet_diagnostic.CA5370.severity = suggestion + +# Use XmlReader for 'XmlSchema.Read()' +dotnet_diagnostic.CA5371.severity = suggestion + +# Use XmlReader for XPathDocument constructor +dotnet_diagnostic.CA5372.severity = suggestion + +# Do not use obsolete key derivation function +dotnet_diagnostic.CA5373.severity = none + +# Do Not Use XslTransform +dotnet_diagnostic.CA5374.severity = suggestion + +# Do Not Use Account Shared Access Signature +dotnet_diagnostic.CA5375.severity = none + +# Use SharedAccessProtocol HttpsOnly +dotnet_diagnostic.CA5376.severity = none + +# Use Container Level Access Policy +dotnet_diagnostic.CA5377.severity = none + +# Do not disable ServicePointManagerSecurityProtocols +dotnet_diagnostic.CA5378.severity = error + +# Ensure Key Derivation Function algorithm is sufficiently strong +dotnet_diagnostic.CA5379.severity = none + +# Do Not Add Certificates To Root Store +dotnet_diagnostic.CA5380.severity = suggestion + +# Ensure Certificates Are Not Added To Root Store +dotnet_diagnostic.CA5381.severity = suggestion + +# Use Secure Cookies In ASP.NET Core +dotnet_diagnostic.CA5382.severity = none + +# Ensure Use Secure Cookies In ASP.NET Core +dotnet_diagnostic.CA5383.severity = none + +# Do Not Use Digital Signature Algorithm (DSA) +dotnet_diagnostic.CA5384.severity = none + +# Use Rivest-Shamir-Adleman (RSA) Algorithm With Sufficient Key Size +dotnet_diagnostic.CA5385.severity = none + +# Avoid hardcoding SecurityProtocolType value +dotnet_diagnostic.CA5386.severity = suggestion + +# Do Not Use Weak Key Derivation Function With Insufficient Iteration Count +dotnet_diagnostic.CA5387.severity = none + +# Ensure Sufficient Iteration Count When Using Weak Key Derivation Function +dotnet_diagnostic.CA5388.severity = none + +# Do Not Add Archive Item's Path To The Target File System Path +dotnet_diagnostic.CA5389.severity = none + +# Do not hard-code encryption key +dotnet_diagnostic.CA5390.severity = none + +# Use antiforgery tokens in ASP.NET Core MVC controllers +dotnet_diagnostic.CA5391.severity = suggestion + +# Use DefaultDllImportSearchPaths attribute for P/Invokes +dotnet_diagnostic.CA5392.severity = none + +# Do not use unsafe DllImportSearchPath value +dotnet_diagnostic.CA5393.severity = none + +# Do not use insecure randomness +dotnet_diagnostic.CA5394.severity = none + +# Miss HttpVerb attribute for action methods +dotnet_diagnostic.CA5395.severity = suggestion + +# Set HttpOnly to true for HttpCookie +dotnet_diagnostic.CA5396.severity = suggestion + +# Do not use deprecated SslProtocols values +dotnet_diagnostic.CA5397.severity = error + +# Avoid hardcoded SslProtocols values +dotnet_diagnostic.CA5398.severity = suggestion + +# HttpClients should enable certificate revocation list checks +dotnet_diagnostic.CA5399.severity = none + +# Ensure HttpClient certificate revocation list check is not disabled +dotnet_diagnostic.CA5400.severity = none + +# Do not use CreateEncryptor with non-default IV +dotnet_diagnostic.CA5401.severity = none + +# Use CreateEncryptor with the default IV +dotnet_diagnostic.CA5402.severity = none + +# Do not hard-code certificate +dotnet_diagnostic.CA5403.severity = none + +# Do not disable token validation checks +dotnet_diagnostic.CA5404.severity = none + +# Do not always skip token validation in delegates +dotnet_diagnostic.CA5405.severity = none + +dotnet_diagnostic.CA9999.severity = none + +dotnet_diagnostic.IL3000.severity = none + +dotnet_diagnostic.IL3001.severity = none + +dotnet_diagnostic.RS1000.severity = none + +dotnet_diagnostic.RS1001.severity = none + +dotnet_diagnostic.RS1002.severity = none + +dotnet_diagnostic.RS1003.severity = none + +dotnet_diagnostic.RS1004.severity = none + +dotnet_diagnostic.RS1005.severity = none + +dotnet_diagnostic.RS1006.severity = none + +dotnet_diagnostic.RS1007.severity = none + +dotnet_diagnostic.RS1008.severity = none + +dotnet_diagnostic.RS1009.severity = none + +dotnet_diagnostic.RS1010.severity = none + +dotnet_diagnostic.RS1011.severity = none + +dotnet_diagnostic.RS1012.severity = none + +dotnet_diagnostic.RS1013.severity = none + +dotnet_diagnostic.RS1014.severity = none + +[*.{cs,vb}] +#### Naming styles #### + +# Naming rules + +dotnet_naming_rule.interface_should_be_begins_with_i.severity = suggestion +dotnet_naming_rule.interface_should_be_begins_with_i.symbols = interface +dotnet_naming_rule.interface_should_be_begins_with_i.style = begins_with_i + +dotnet_naming_rule.types_should_be_pascal_case.severity = suggestion +dotnet_naming_rule.types_should_be_pascal_case.symbols = types +dotnet_naming_rule.types_should_be_pascal_case.style = pascal_case + +dotnet_naming_rule.non_field_members_should_be_pascal_case.severity = suggestion +dotnet_naming_rule.non_field_members_should_be_pascal_case.symbols = non_field_members +dotnet_naming_rule.non_field_members_should_be_pascal_case.style = pascal_case + +# Symbol specifications + +dotnet_naming_symbols.interface.applicable_kinds = interface +dotnet_naming_symbols.interface.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.interface.required_modifiers = + +dotnet_naming_symbols.types.applicable_kinds = class, struct, interface, enum +dotnet_naming_symbols.types.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.types.required_modifiers = + +dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method +dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.non_field_members.required_modifiers = + +# Naming styles + +dotnet_naming_style.begins_with_i.required_prefix = I +dotnet_naming_style.begins_with_i.required_suffix = +dotnet_naming_style.begins_with_i.word_separator = +dotnet_naming_style.begins_with_i.capitalization = pascal_case + +dotnet_naming_style.pascal_case.required_prefix = +dotnet_naming_style.pascal_case.required_suffix = +dotnet_naming_style.pascal_case.word_separator = +dotnet_naming_style.pascal_case.capitalization = pascal_case + +dotnet_naming_style.pascal_case.required_prefix = +dotnet_naming_style.pascal_case.required_suffix = +dotnet_naming_style.pascal_case.word_separator = +dotnet_naming_style.pascal_case.capitalization = pascal_case +dotnet_style_operator_placement_when_wrapping = beginning_of_line +tab_width = 4 +indent_size = 4 +end_of_line = crlf +dotnet_style_coalesce_expression = true:suggestion +dotnet_style_null_propagation = true:suggestion +dotnet_style_prefer_is_null_check_over_reference_equality_method = true:suggestion +dotnet_style_prefer_auto_properties = true:silent +dotnet_style_object_initializer = true:suggestion +dotnet_style_prefer_collection_expression = true:suggestion +dotnet_style_collection_initializer = true:suggestion +dotnet_style_prefer_simplified_boolean_expressions = true:suggestion +dotnet_style_prefer_conditional_expression_over_assignment = true:silent +dotnet_style_prefer_conditional_expression_over_return = true:silent +dotnet_style_explicit_tuple_names = true:suggestion +dotnet_style_prefer_inferred_tuple_names = true:suggestion +dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion +dotnet_style_prefer_compound_assignment = true:suggestion +dotnet_style_prefer_simplified_interpolation = true:suggestion +dotnet_style_namespace_match_folder = true:suggestion +dotnet_style_readonly_field = true:suggestion +dotnet_style_predefined_type_for_locals_parameters_members = true:silent +dotnet_style_predefined_type_for_member_access = true:silent +dotnet_style_require_accessibility_modifiers = for_non_interface_members:silent +dotnet_style_allow_multiple_blank_lines_experimental = true:silent +dotnet_style_allow_statement_immediately_after_block_experimental = true:silent +dotnet_code_quality_unused_parameters = all:suggestion + +[*.cs] +csharp_indent_labels = one_less_than_current +csharp_using_directive_placement = outside_namespace:silent +csharp_prefer_simple_using_statement = true:suggestion +csharp_prefer_braces = true:silent +csharp_style_namespace_declarations = block_scoped:silent +csharp_style_prefer_method_group_conversion = true:silent +csharp_style_prefer_top_level_statements = true:silent +csharp_style_prefer_primary_constructors = true:suggestion +csharp_style_expression_bodied_methods = false:silent +csharp_style_expression_bodied_constructors = false:silent +csharp_style_expression_bodied_operators = false:silent +csharp_style_expression_bodied_properties = true:silent +csharp_style_expression_bodied_indexers = true:silent +csharp_style_expression_bodied_accessors = true:silent +csharp_style_expression_bodied_lambdas = true:silent +csharp_style_expression_bodied_local_functions = false:silent +csharp_style_throw_expression = true:suggestion +csharp_style_prefer_null_check_over_type_check = true:suggestion +csharp_prefer_simple_default_expression = true:suggestion +csharp_style_prefer_index_operator = true:suggestion +csharp_style_prefer_local_over_anonymous_function = true:suggestion +csharp_style_implicit_object_creation_when_type_is_apparent = true:suggestion +csharp_style_prefer_range_operator = true:suggestion +csharp_style_prefer_tuple_swap = true:suggestion +csharp_style_prefer_utf8_string_literals = true:suggestion +csharp_style_inlined_variable_declaration = true:suggestion +csharp_style_deconstructed_variable_declaration = true:suggestion +csharp_style_unused_value_assignment_preference = discard_variable:suggestion +csharp_style_unused_value_expression_statement_preference = discard_variable:silent +csharp_style_prefer_readonly_struct_member = true:suggestion +csharp_style_prefer_readonly_struct = true:suggestion +csharp_prefer_static_local_function = true:suggestion +csharp_style_allow_embedded_statements_on_same_line_experimental = true:silent +csharp_style_allow_blank_lines_between_consecutive_braces_experimental = true:silent +csharp_style_allow_blank_line_after_colon_in_constructor_initializer_experimental = true:silent +csharp_style_allow_blank_line_after_token_in_conditional_expression_experimental = true:silent +csharp_style_allow_blank_line_after_token_in_arrow_expression_clause_experimental = true:silent +csharp_style_conditional_delegate_call = true:suggestion +csharp_space_around_binary_operators = before_and_after \ No newline at end of file diff --git a/src/Flattener/CallRecordInsights.Flattener.csproj b/src/Flattener/CallRecordInsights.Flattener.csproj new file mode 100644 index 0000000..f9237ac --- /dev/null +++ b/src/Flattener/CallRecordInsights.Flattener.csproj @@ -0,0 +1,13 @@ + + + + net6.0;net7.0 + latest + enable + + + + + + + diff --git a/src/Flattener/Extensions/IKustoCallRecordHelpers.cs b/src/Flattener/Extensions/IKustoCallRecordHelpers.cs new file mode 100644 index 0000000..16e68d4 --- /dev/null +++ b/src/Flattener/Extensions/IKustoCallRecordHelpers.cs @@ -0,0 +1,544 @@ +using CallRecordInsights.Flattener; +using CallRecordInsights.Models; +using Microsoft.Graph.Models.CallRecords; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text.Json.Nodes; + +namespace CallRecordInsights.Extensions +{ + public static class IKustoCallRecordHelpers + { + /// + /// Converts a to a collection of using the provided . + /// + /// + /// + /// + /// + public static IEnumerable AsKustoCallRecords(this CallRecord callRecord, IJsonProcessor flattener, string tenantIdContext) + { + var flattenerResults = flattener.ProcessNode(callRecord.SerializeAsString()); + if (flattenerResults?.Any() != true) + return Enumerable.Empty(); + + var results = new List(); + foreach (var flattenedResult in flattenerResults) + { + var kustoCallRecord = FromJsonDictionary(flattenedResult); + kustoCallRecord.CallRecordTenantIdContext = tenantIdContext; + results.Add(kustoCallRecord); + } + return results; + } + + public static readonly IJsonFlattenerConfiguration DefaultConfiguration = new JsonFlattenerConfiguration( + new FlattenerOptions() + { + CaseInsensitivePropertyNameMatching = false, + ColumnObjectMap = new Dictionary + { + { nameof(IKustoCallRecord.CallId), "$.id" }, + { nameof(IKustoCallRecord.SessionId), "$.sessions[*].id" }, + { nameof(IKustoCallRecord.StreamId), "$.sessions[*].segments[*].media[*].streams[*].streamId" }, + { nameof(IKustoCallRecord.StreamDirection), "$.sessions[*].segments[*].media[*].streams[*].streamDirection" }, + { nameof(IKustoCallRecord.MediaLabel), "$.sessions[*].segments[*].media[*].label" }, + { nameof(IKustoCallRecord.CallStartTime), "$.startDateTime" }, + { nameof(IKustoCallRecord.CallEndTime), "$.endDateTime" }, + { nameof(IKustoCallRecord.SessionStartTime), "$.sessions[*].startDateTime" }, + { nameof(IKustoCallRecord.SessionEndTime), "$.sessions[*].endDateTime" }, + { nameof(IKustoCallRecord.LastModifiedDateTimeOffset), "$.lastModifiedDateTime" }, + { nameof(IKustoCallRecord.CallType), "$.type" }, + { nameof(IKustoCallRecord.JoinWebUrl), "$.joinWebUrl" }, + { nameof(IKustoCallRecord.VideoCodec), "$.sessions[*].segments[*].media[*].streams[*].videoCodec" }, + { nameof(IKustoCallRecord.AudioCodec), "$.sessions[*].segments[*].media[*].streams[*].audioCodec" }, + { nameof(IKustoCallRecord.WasMediaBypassed), "$.sessions[*].segments[*].media[*].streams[*].wasMediaBypassed" }, + { nameof(IKustoCallRecord.FailureStage), "$.sessions[*].failureInfo.stage" }, + { nameof(IKustoCallRecord.FailureReason), "$.sessions[*].failureInfo.reason" }, + { nameof(IKustoCallRecord.PacketUtilization), "$.sessions[*].segments[*].media[*].streams[*].packetUtilization" }, + { nameof(IKustoCallRecord.AverageBandwidthEstimate), "$.sessions[*].segments[*].media[*].streams[*].averageBandwidthEstimate" }, + { nameof(IKustoCallRecord.AverageJitter), "$.sessions[*].segments[*].media[*].streams[*].averageJitter" }, + { nameof(IKustoCallRecord.MaxJitter), "$.sessions[*].segments[*].media[*].streams[*].maxJitter" }, + { nameof(IKustoCallRecord.AverageRoundTripTime), "$.sessions[*].segments[*].media[*].streams[*].averageRoundTripTime" }, + { nameof(IKustoCallRecord.MaxRoundTripTime), "$.sessions[*].segments[*].media[*].streams[*].maxRoundTripTime" }, + { nameof(IKustoCallRecord.AverageAudioNetworkJitter), "$.sessions[*].segments[*].media[*].streams[*].averageAudioNetworkJitter" }, + { nameof(IKustoCallRecord.MaxAudioNetworkJitter), "$.sessions[*].segments[*].media[*].streams[*].maxAudioNetworkJitter" }, + { nameof(IKustoCallRecord.AverageAudioDegradation), "$.sessions[*].segments[*].media[*].streams[*].averageAudioDegradation" }, + { nameof(IKustoCallRecord.AveragePacketLossRate), "$.sessions[*].segments[*].media[*].streams[*].averagePacketLossRate" }, + { nameof(IKustoCallRecord.MaxPacketLossRate), "$.sessions[*].segments[*].media[*].streams[*].maxPacketLossRate" }, + { nameof(IKustoCallRecord.PostForwardErrorCorrectionPacketLossRate), "$.sessions[*].segments[*].media[*].streams[*].postForwardErrorCorrectionPacketLossRate" }, + { nameof(IKustoCallRecord.AverageRatioOfConcealedSamples), "$.sessions[*].segments[*].media[*].streams[*].averageRatioOfConcealedSamples" }, + { nameof(IKustoCallRecord.MaxRatioOfConcealedSamples), "$.sessions[*].segments[*].media[*].streams[*].maxRatioOfConcealedSamples" }, + { nameof(IKustoCallRecord.LowVideoProcessingCapabilityRatio), "$.sessions[*].segments[*].media[*].streams[*].lowVideoProcessingCapabilityRatio" }, + { nameof(IKustoCallRecord.AverageVideoFrameRate), "$.sessions[*].segments[*].media[*].streams[*].averageVideoFrameRate" }, + { nameof(IKustoCallRecord.AverageReceivedFrameRate), "$.sessions[*].segments[*].media[*].streams[*].averageReceivedFrameRate" }, + { nameof(IKustoCallRecord.LowFrameRateRatio), "$.sessions[*].segments[*].media[*].streams[*].lowFrameRateRatio" }, + { nameof(IKustoCallRecord.AverageVideoPacketLossRate), "$.sessions[*].segments[*].media[*].streams[*].averageVideoPacketLossRate" }, + { nameof(IKustoCallRecord.AverageVideoFrameLossPercentage), "$.sessions[*].segments[*].media[*].streams[*].averageVideoFrameLossPercentage" }, + { nameof(IKustoCallRecord.Organizer_UserDisplayName), "$.organizer.user.displayName" }, + { nameof(IKustoCallRecord.Organizer_UserId), "$.organizer.user.id" }, + { nameof(IKustoCallRecord.Organizer_UserTenantId), "$.organizer.user.tenantId" }, + { nameof(IKustoCallRecord.Organizer_ApplicationInstanceDisplayName), "$.organizer.applicationInstance.displayName" }, + { nameof(IKustoCallRecord.Organizer_ApplicationInstanceId), "$.organizer.applicationInstance.id" }, + { nameof(IKustoCallRecord.Organizer_ApplicationInstanceTenantId), "$.organizer.applicationInstance.tenantId" }, + { nameof(IKustoCallRecord.Organizer_GuestDisplayName), "$.organizer.guest.displayName" }, + { nameof(IKustoCallRecord.Organizer_GuestId), "$.organizer.guest.id" }, + { nameof(IKustoCallRecord.Organizer_GuestTenantId), "$.organizer.guest.tenantId" }, + { nameof(IKustoCallRecord.Organizer_PhoneDisplayName), "$.organizer.phone.displayName" }, + { nameof(IKustoCallRecord.Organizer_PhoneId), "$.organizer.phone.id" }, + { nameof(IKustoCallRecord.Organizer_PhoneTenantId), "$.organizer.phone.tenantId" }, + { nameof(IKustoCallRecord.Organizer_OnPremisesDisplayName), "$.organizer.onPremises.displayName" }, + { nameof(IKustoCallRecord.Organizer_OnPremisesId), "$.organizer.onPremises.id" }, + { nameof(IKustoCallRecord.Organizer_OnPremisesTenantId), "$.organizer.onPremises.tenantId" }, + { nameof(IKustoCallRecord.Organizer_EncryptedDisplayName), "$.organizer.encrypted.displayName" }, + { nameof(IKustoCallRecord.Organizer_EncryptedId), "$.organizer.encrypted.id" }, + { nameof(IKustoCallRecord.Organizer_EncryptedTenantId), "$.organizer.encrypted.tenantId" }, + { nameof(IKustoCallRecord.Organizer_AcsUserDisplayName), "$.organizer.acsUser.displayName" }, + { nameof(IKustoCallRecord.Organizer_AcsUserId), "$.organizer.acsUser.id" }, + { nameof(IKustoCallRecord.Organizer_AcsUserTenantId), "$.organizer.acsUser.tenantId" }, + { nameof(IKustoCallRecord.Organizer_SpoolUserDisplayName), "$.organizer.spoolUser.displayName" }, + { nameof(IKustoCallRecord.Organizer_SpoolUserId), "$.organizer.spoolUser.id" }, + { nameof(IKustoCallRecord.Organizer_SpoolUserTenantId), "$.organizer.spoolUser.tenantId" }, + { nameof(IKustoCallRecord.Organizer_AcsApplicationInstanceDisplayName), "$.organizer.acsApplicationInstance.displayName" }, + { nameof(IKustoCallRecord.Organizer_AcsApplicationInstanceId), "$.organizer.acsApplicationInstance.id" }, + { nameof(IKustoCallRecord.Organizer_AcsApplicationInstanceTenantId), "$.organizer.acsApplicationInstance.tenantId" }, + { nameof(IKustoCallRecord.Organizer_SpoolApplicationInstanceDisplayName), "$.organizer.spoolApplicationInstance.displayName" }, + { nameof(IKustoCallRecord.Organizer_SpoolApplicationInstanceId), "$.organizer.spoolApplicationInstance.id" }, + { nameof(IKustoCallRecord.Organizer_SpoolApplicationInstanceTenantId), "$.organizer.spoolApplicationInstance.tenantId" }, + { nameof(IKustoCallRecord.Callee_UserDisplayName), "$.sessions[*].segments[*].callee.identity.user.displayName" }, + { nameof(IKustoCallRecord.Callee_UserId), "$.sessions[*].segments[*].callee.identity.user.id" }, + { nameof(IKustoCallRecord.Callee_UserTenantId), "$.sessions[*].segments[*].callee.identity.user.tenantId" }, + { nameof(IKustoCallRecord.Callee_ApplicationInstanceDisplayName), "$.sessions[*].segments[*].callee.identity.applicationInstance.displayName" }, + { nameof(IKustoCallRecord.Callee_ApplicationInstanceId), "$.sessions[*].segments[*].callee.identity.applicationInstance.id" }, + { nameof(IKustoCallRecord.Callee_ApplicationInstanceTenantId), "$.sessions[*].segments[*].callee.identity.applicationInstance.tenantId" }, + { nameof(IKustoCallRecord.Callee_GuestDisplayName), "$.sessions[*].segments[*].callee.identity.guest.displayName" }, + { nameof(IKustoCallRecord.Callee_GuestId), "$.sessions[*].segments[*].callee.identity.guest.id" }, + { nameof(IKustoCallRecord.Callee_GuestTenantId), "$.sessions[*].segments[*].callee.identity.guest.tenantId" }, + { nameof(IKustoCallRecord.Callee_PhoneDisplayName), "$.sessions[*].segments[*].callee.identity.phone.displayName" }, + { nameof(IKustoCallRecord.Callee_PhoneId), "$.sessions[*].segments[*].callee.identity.phone.id" }, + { nameof(IKustoCallRecord.Callee_PhoneTenantId), "$.sessions[*].segments[*].callee.identity.phone.tenantId" }, + { nameof(IKustoCallRecord.Callee_OnPremisesDisplayName), "$.sessions[*].segments[*].callee.identity.onPremises.displayName" }, + { nameof(IKustoCallRecord.Callee_OnPremisesId), "$.sessions[*].segments[*].callee.identity.onPremises.id" }, + { nameof(IKustoCallRecord.Callee_OnPremisesTenantId), "$.sessions[*].segments[*].callee.identity.onPremises.tenantId" }, + { nameof(IKustoCallRecord.Callee_EncryptedDisplayName), "$.sessions[*].segments[*].callee.identity.encrypted.displayName" }, + { nameof(IKustoCallRecord.Callee_EncryptedId), "$.sessions[*].segments[*].callee.identity.encrypted.id" }, + { nameof(IKustoCallRecord.Callee_EncryptedTenantId), "$.sessions[*].segments[*].callee.identity.encrypted.tenantId" }, + { nameof(IKustoCallRecord.Callee_AcsUserDisplayName), "$.sessions[*].segments[*].callee.identity.acsUser.displayName" }, + { nameof(IKustoCallRecord.Callee_AcsUserId), "$.sessions[*].segments[*].callee.identity.acsUser.id" }, + { nameof(IKustoCallRecord.Callee_AcsUserTenantId), "$.sessions[*].segments[*].callee.identity.acsUser.tenantId" }, + { nameof(IKustoCallRecord.Callee_SpoolUserDisplayName), "$.sessions[*].segments[*].callee.identity.spoolUser.displayName" }, + { nameof(IKustoCallRecord.Callee_SpoolUserId), "$.sessions[*].segments[*].callee.identity.spoolUser.id" }, + { nameof(IKustoCallRecord.Callee_SpoolUserTenantId), "$.sessions[*].segments[*].callee.identity.spoolUser.tenantId" }, + { nameof(IKustoCallRecord.Callee_AcsApplicationInstanceDisplayName), "$.sessions[*].segments[*].callee.identity.acsApplicationInstance.displayName" }, + { nameof(IKustoCallRecord.Callee_AcsApplicationInstanceId), "$.sessions[*].segments[*].callee.identity.acsApplicationInstance.id" }, + { nameof(IKustoCallRecord.Callee_AcsApplicationInstanceTenantId), "$.sessions[*].segments[*].callee.identity.acsApplicationInstance.tenantId" }, + { nameof(IKustoCallRecord.Callee_SpoolApplicationInstanceDisplayName), "$.sessions[*].segments[*].callee.identity.spoolApplicationInstance.displayName" }, + { nameof(IKustoCallRecord.Callee_SpoolApplicationInstanceId), "$.sessions[*].segments[*].callee.identity.spoolApplicationInstance.id" }, + { nameof(IKustoCallRecord.Callee_SpoolApplicationInstanceTenantId), "$.sessions[*].segments[*].callee.identity.spoolApplicationInstance.tenantId" }, + { nameof(IKustoCallRecord.Callee_EndpointType), "$.sessions[*].segments[*].callee['@odata.type']" }, + { nameof(IKustoCallRecord.Callee_ProductFamily), "$.sessions[*].segments[*].callee.userAgent.productFamily" }, + { nameof(IKustoCallRecord.Callee_Platform), "$.sessions[*].segments[*].callee.userAgent.platform" }, + { nameof(IKustoCallRecord.Callee_UserAgentHeaderValue), "$.sessions[*].segments[*].callee.userAgent.headerValue" }, + { nameof(IKustoCallRecord.Callee_ServiceRole), "$.sessions[*].segments[*].callee.userAgent.role" }, + { nameof(IKustoCallRecord.Callee_ApplicationVersion), "$.sessions[*].segments[*].callee.userAgent.applicationVersion" }, + { nameof(IKustoCallRecord.Callee_AzureAdAppId), "$.sessions[*].segments[*].callee.userAgent.azureAdAppId" }, + { nameof(IKustoCallRecord.Callee_CommunicationServiceId), "$.sessions[*].segments[*].callee.userAgent.communicationServiceId" }, + { nameof(IKustoCallRecord.Callee_ConnectionType), "$.sessions[*].segments[*].media[*].calleeNetwork.connectionType" }, + { nameof(IKustoCallRecord.Callee_ReflexiveIPAddress), "$.sessions[*].segments[*].media[*].calleeNetwork.reflexiveIPAddress" }, + { nameof(IKustoCallRecord.Callee_Subnet), "$.sessions[*].segments[*].media[*].calleeNetwork.subnet" }, + { nameof(IKustoCallRecord.Callee_IpAddress), "$.sessions[*].segments[*].media[*].calleeNetwork.ipAddress" }, + { nameof(IKustoCallRecord.Callee_MacAddress), "$.sessions[*].segments[*].media[*].calleeNetwork.macAddress" }, + { nameof(IKustoCallRecord.Callee_LinkSpeed), "$.sessions[*].segments[*].media[*].calleeNetwork.linkSpeed" }, + { nameof(IKustoCallRecord.Callee_NetworkTransportProtocol), "$.sessions[*].segments[*].media[*].calleeNetwork.networkTransportProtocol" }, + { nameof(IKustoCallRecord.Callee_Port), "$.sessions[*].segments[*].media[*].calleeNetwork.port" }, + { nameof(IKustoCallRecord.Callee_RelayIPAddress), "$.sessions[*].segments[*].media[*].calleeNetwork.relayIPAddress" }, + { nameof(IKustoCallRecord.Callee_RelayPort), "$.sessions[*].segments[*].media[*].calleeNetwork.relayPort" }, + { nameof(IKustoCallRecord.Callee_DnsSuffix), "$.sessions[*].segments[*].media[*].calleeNetwork.dnsSuffix" }, + { nameof(IKustoCallRecord.Callee_TraceRouteHops), "$.sessions[*].segments[*].media[*].calleeNetwork.traceRouteHops" }, + { nameof(IKustoCallRecord.Callee_BSSID), "$.sessions[*].segments[*].media[*].calleeNetwork.basicServiceSetIdentifier" }, + { nameof(IKustoCallRecord.Callee_WifiRadioType), "$.sessions[*].segments[*].media[*].calleeNetwork.wifiRadioType" }, + { nameof(IKustoCallRecord.Callee_WifiBand), "$.sessions[*].segments[*].media[*].calleeNetwork.wifiBand" }, + { nameof(IKustoCallRecord.Callee_WifiChannel), "$.sessions[*].segments[*].media[*].calleeNetwork.wifiChannel" }, + { nameof(IKustoCallRecord.Callee_WifiSignalStrength), "$.sessions[*].segments[*].media[*].calleeNetwork.wifiSignalStrength" }, + { nameof(IKustoCallRecord.Callee_WifiBatteryCharge), "$.sessions[*].segments[*].media[*].calleeNetwork.wifiBatteryCharge" }, + { nameof(IKustoCallRecord.Callee_WifiMicrosoftDriver), "$.sessions[*].segments[*].media[*].calleeNetwork.wifiMicrosoftDriver" }, + { nameof(IKustoCallRecord.Callee_WifiMicrosoftDriverVersion), "$.sessions[*].segments[*].media[*].calleeNetwork.wifiMicrosoftDriverVersion" }, + { nameof(IKustoCallRecord.Callee_WifiVendorDriver), "$.sessions[*].segments[*].media[*].calleeNetwork.wifiVendorDriver" }, + { nameof(IKustoCallRecord.Callee_WifiVendorDriverVersion), "$.sessions[*].segments[*].media[*].calleeNetwork.wifiVendorDriverVersion" }, + { nameof(IKustoCallRecord.Callee_CaptureDeviceName), "$.sessions[*].segments[*].media[*].calleeDevice.captureDeviceName" }, + { nameof(IKustoCallRecord.Callee_CaptureDeviceDriver), "$.sessions[*].segments[*].media[*].calleeDevice.captureDeviceDriver" }, + { nameof(IKustoCallRecord.Callee_RenderDeviceName), "$.sessions[*].segments[*].media[*].calleeDevice.renderDeviceName" }, + { nameof(IKustoCallRecord.Callee_RenderDeviceDriver), "$.sessions[*].segments[*].media[*].calleeDevice.renderDeviceDriver" }, + { nameof(IKustoCallRecord.Callee_SentSignalLevel), "$.sessions[*].segments[*].media[*].calleeDevice.sentSignalLevel" }, + { nameof(IKustoCallRecord.Callee_SentNoiseLevel), "$.sessions[*].segments[*].media[*].calleeDevice.sentNoiseLevel" }, + { nameof(IKustoCallRecord.Callee_MicGlitchRate), "$.sessions[*].segments[*].media[*].calleeDevice.micGlitchRate" }, + { nameof(IKustoCallRecord.Callee_ReceivedSignalLevel), "$.sessions[*].segments[*].media[*].calleeDevice.receivedSignalLevel" }, + { nameof(IKustoCallRecord.Callee_ReceivedNoiseLevel), "$.sessions[*].segments[*].media[*].calleeDevice.receivedNoiseLevel" }, + { nameof(IKustoCallRecord.Callee_SpeakerGlitchRate), "$.sessions[*].segments[*].media[*].calleeDevice.speakerGlitchRate" }, + { nameof(IKustoCallRecord.Callee_HowlingEventCount), "$.sessions[*].segments[*].media[*].calleeDevice.howlingEventCount" }, + { nameof(IKustoCallRecord.Callee_InitialSignalLevelRootMeanSquare), "$.sessions[*].segments[*].media[*].calleeDevice.initialSignalLevelRootMeanSquare" }, + { nameof(IKustoCallRecord.Callee_DeviceGlitchEventRatio), "$.sessions[*].segments[*].media[*].calleeDevice.deviceGlitchEventRatio" }, + { nameof(IKustoCallRecord.Callee_DeviceClippingEventRatio), "$.sessions[*].segments[*].media[*].calleeDevice.deviceClippingEventRatio" }, + { nameof(IKustoCallRecord.Callee_LowSpeechToNoiseEventRatio), "$.sessions[*].segments[*].media[*].calleeDevice.lowSpeechToNoiseEventRatio" }, + { nameof(IKustoCallRecord.Callee_CaptureNotFunctioningEventRatio), "$.sessions[*].segments[*].media[*].calleeDevice.captureNotFunctioningEventRatio" }, + { nameof(IKustoCallRecord.Callee_SentQualityEventRatio), "$.sessions[*].segments[*].media[*].calleeNetwork.sentQualityEventRatio" }, + { nameof(IKustoCallRecord.Callee_LowSpeechLevelEventRatio), "$.sessions[*].segments[*].media[*].calleeDevice.lowSpeechLevelEventRatio" }, + { nameof(IKustoCallRecord.Callee_RenderNotFunctioningEventRatio), "$.sessions[*].segments[*].media[*].calleeDevice.renderNotFunctioningEventRatio" }, + { nameof(IKustoCallRecord.Callee_ReceivedQualityEventRatio), "$.sessions[*].segments[*].media[*].calleeNetwork.receivedQualityEventRatio" }, + { nameof(IKustoCallRecord.Callee_RenderZeroVolumeEventRatio), "$.sessions[*].segments[*].media[*].calleeDevice.renderZeroVolumeEventRatio" }, + { nameof(IKustoCallRecord.Callee_RenderMuteEventRatio), "$.sessions[*].segments[*].media[*].calleeDevice.renderMuteEventRatio" }, + { nameof(IKustoCallRecord.Callee_CpuInsufficentEventRatio), "$.sessions[*].segments[*].media[*].calleeDevice.cpuInsufficentEventRatio" }, + { nameof(IKustoCallRecord.Callee_DelayEventRatio), "$.sessions[*].segments[*].media[*].calleeNetwork.delayEventRatio" }, + { nameof(IKustoCallRecord.Callee_BandwidthLowEventRatio), "$.sessions[*].segments[*].media[*].calleeNetwork.bandwidthLowEventRatio" }, + { nameof(IKustoCallRecord.Callee_FeedbackRating), "$.sessions[*].segments[*].callee.feedback.rating" }, + { nameof(IKustoCallRecord.Callee_FeedbackText), "$.sessions[*].segments[*].callee.feedback.text" }, + { nameof(IKustoCallRecord.Callee_FeedbackTokens), "$.sessions[*].segments[*].callee.feedback.tokens" }, + { nameof(IKustoCallRecord.Caller_UserDisplayName), "$.sessions[*].segments[*].caller.identity.user.displayName" }, + { nameof(IKustoCallRecord.Caller_UserId), "$.sessions[*].segments[*].caller.identity.user.id" }, + { nameof(IKustoCallRecord.Caller_UserTenantId), "$.sessions[*].segments[*].caller.identity.user.tenantId" }, + { nameof(IKustoCallRecord.Caller_ApplicationInstanceDisplayName), "$.sessions[*].segments[*].caller.identity.applicationInstance.displayName" }, + { nameof(IKustoCallRecord.Caller_ApplicationInstanceId), "$.sessions[*].segments[*].caller.identity.applicationInstance.id" }, + { nameof(IKustoCallRecord.Caller_ApplicationInstanceTenantId), "$.sessions[*].segments[*].caller.identity.applicationInstance.tenantId" }, + { nameof(IKustoCallRecord.Caller_GuestDisplayName), "$.sessions[*].segments[*].caller.identity.guest.displayName" }, + { nameof(IKustoCallRecord.Caller_GuestId), "$.sessions[*].segments[*].caller.identity.guest.id" }, + { nameof(IKustoCallRecord.Caller_GuestTenantId), "$.sessions[*].segments[*].caller.identity.guest.tenantId" }, + { nameof(IKustoCallRecord.Caller_PhoneDisplayName), "$.sessions[*].segments[*].caller.identity.phone.displayName" }, + { nameof(IKustoCallRecord.Caller_PhoneId), "$.sessions[*].segments[*].caller.identity.phone.id" }, + { nameof(IKustoCallRecord.Caller_PhoneTenantId), "$.sessions[*].segments[*].caller.identity.phone.tenantId" }, + { nameof(IKustoCallRecord.Caller_OnPremisesDisplayName), "$.sessions[*].segments[*].caller.identity.onPremises.displayName" }, + { nameof(IKustoCallRecord.Caller_OnPremisesId), "$.sessions[*].segments[*].caller.identity.onPremises.id" }, + { nameof(IKustoCallRecord.Caller_OnPremisesTenantId), "$.sessions[*].segments[*].caller.identity.onPremises.tenantId" }, + { nameof(IKustoCallRecord.Caller_EncryptedDisplayName), "$.sessions[*].segments[*].caller.identity.encrypted.displayName" }, + { nameof(IKustoCallRecord.Caller_EncryptedId), "$.sessions[*].segments[*].caller.identity.encrypted.id" }, + { nameof(IKustoCallRecord.Caller_EncryptedTenantId), "$.sessions[*].segments[*].caller.identity.encrypted.tenantId" }, + { nameof(IKustoCallRecord.Caller_AcsUserDisplayName), "$.sessions[*].segments[*].caller.identity.acsUser.displayName" }, + { nameof(IKustoCallRecord.Caller_AcsUserId), "$.sessions[*].segments[*].caller.identity.acsUser.id" }, + { nameof(IKustoCallRecord.Caller_AcsUserTenantId), "$.sessions[*].segments[*].caller.identity.acsUser.tenantId" }, + { nameof(IKustoCallRecord.Caller_SpoolUserDisplayName), "$.sessions[*].segments[*].caller.identity.spoolUser.displayName" }, + { nameof(IKustoCallRecord.Caller_SpoolUserId), "$.sessions[*].segments[*].caller.identity.spoolUser.id" }, + { nameof(IKustoCallRecord.Caller_SpoolUserTenantId), "$.sessions[*].segments[*].caller.identity.spoolUser.tenantId" }, + { nameof(IKustoCallRecord.Caller_AcsApplicationInstanceDisplayName), "$.sessions[*].segments[*].caller.identity.acsApplicationInstance.displayName" }, + { nameof(IKustoCallRecord.Caller_AcsApplicationInstanceId), "$.sessions[*].segments[*].caller.identity.acsApplicationInstance.id" }, + { nameof(IKustoCallRecord.Caller_AcsApplicationInstanceTenantId), "$.sessions[*].segments[*].caller.identity.acsApplicationInstance.tenantId" }, + { nameof(IKustoCallRecord.Caller_SpoolApplicationInstanceDisplayName), "$.sessions[*].segments[*].caller.identity.spoolApplicationInstance.displayName" }, + { nameof(IKustoCallRecord.Caller_SpoolApplicationInstanceId), "$.sessions[*].segments[*].caller.identity.spoolApplicationInstance.id" }, + { nameof(IKustoCallRecord.Caller_SpoolApplicationInstanceTenantId), "$.sessions[*].segments[*].caller.identity.spoolApplicationInstance.tenantId" }, + { nameof(IKustoCallRecord.Caller_EndpointType), "$.sessions[*].segments[*].caller['@odata.type']" }, + { nameof(IKustoCallRecord.Caller_ProductFamily), "$.sessions[*].segments[*].caller.userAgent.productFamily" }, + { nameof(IKustoCallRecord.Caller_Platform), "$.sessions[*].segments[*].caller.userAgent.platform" }, + { nameof(IKustoCallRecord.Caller_UserAgentHeaderValue), "$.sessions[*].segments[*].caller.userAgent.headerValue" }, + { nameof(IKustoCallRecord.Caller_ServiceRole), "$.sessions[*].segments[*].caller.userAgent.role" }, + { nameof(IKustoCallRecord.Caller_ApplicationVersion), "$.sessions[*].segments[*].caller.userAgent.applicationVersion" }, + { nameof(IKustoCallRecord.Caller_AzureAdAppId), "$.sessions[*].segments[*].caller.userAgent.azureAdAppId" }, + { nameof(IKustoCallRecord.Caller_CommunicationServiceId), "$.sessions[*].segments[*].caller.userAgent.communicationServiceId" }, + { nameof(IKustoCallRecord.Caller_ConnectionType), "$.sessions[*].segments[*].media[*].callerNetwork.connectionType" }, + { nameof(IKustoCallRecord.Caller_ReflexiveIPAddress), "$.sessions[*].segments[*].media[*].callerNetwork.reflexiveIPAddress" }, + { nameof(IKustoCallRecord.Caller_Subnet), "$.sessions[*].segments[*].media[*].callerNetwork.subnet" }, + { nameof(IKustoCallRecord.Caller_IpAddress), "$.sessions[*].segments[*].media[*].callerNetwork.ipAddress" }, + { nameof(IKustoCallRecord.Caller_MacAddress), "$.sessions[*].segments[*].media[*].callerNetwork.macAddress" }, + { nameof(IKustoCallRecord.Caller_LinkSpeed), "$.sessions[*].segments[*].media[*].callerNetwork.linkSpeed" }, + { nameof(IKustoCallRecord.Caller_NetworkTransportProtocol), "$.sessions[*].segments[*].media[*].callerNetwork.networkTransportProtocol" }, + { nameof(IKustoCallRecord.Caller_Port), "$.sessions[*].segments[*].media[*].callerNetwork.port" }, + { nameof(IKustoCallRecord.Caller_RelayIPAddress), "$.sessions[*].segments[*].media[*].callerNetwork.relayIPAddress" }, + { nameof(IKustoCallRecord.Caller_RelayPort), "$.sessions[*].segments[*].media[*].callerNetwork.relayPort" }, + { nameof(IKustoCallRecord.Caller_DnsSuffix), "$.sessions[*].segments[*].media[*].callerNetwork.dnsSuffix" }, + { nameof(IKustoCallRecord.Caller_TraceRouteHops), "$.sessions[*].segments[*].media[*].callerNetwork.traceRouteHops" }, + { nameof(IKustoCallRecord.Caller_BSSID), "$.sessions[*].segments[*].media[*].callerNetwork.basicServiceSetIdentifier" }, + { nameof(IKustoCallRecord.Caller_WifiRadioType), "$.sessions[*].segments[*].media[*].callerNetwork.wifiRadioType" }, + { nameof(IKustoCallRecord.Caller_WifiBand), "$.sessions[*].segments[*].media[*].callerNetwork.wifiBand" }, + { nameof(IKustoCallRecord.Caller_WifiChannel), "$.sessions[*].segments[*].media[*].callerNetwork.wifiChannel" }, + { nameof(IKustoCallRecord.Caller_WifiSignalStrength), "$.sessions[*].segments[*].media[*].callerNetwork.wifiSignalStrength" }, + { nameof(IKustoCallRecord.Caller_WifiBatteryCharge), "$.sessions[*].segments[*].media[*].callerNetwork.wifiBatteryCharge" }, + { nameof(IKustoCallRecord.Caller_WifiMicrosoftDriver), "$.sessions[*].segments[*].media[*].callerNetwork.wifiMicrosoftDriver" }, + { nameof(IKustoCallRecord.Caller_WifiMicrosoftDriverVersion), "$.sessions[*].segments[*].media[*].callerNetwork.wifiMicrosoftDriverVersion" }, + { nameof(IKustoCallRecord.Caller_WifiVendorDriver), "$.sessions[*].segments[*].media[*].callerNetwork.wifiVendorDriver" }, + { nameof(IKustoCallRecord.Caller_WifiVendorDriverVersion), "$.sessions[*].segments[*].media[*].callerNetwork.wifiVendorDriverVersion" }, + { nameof(IKustoCallRecord.Caller_CaptureDeviceName), "$.sessions[*].segments[*].media[*].callerDevice.captureDeviceName" }, + { nameof(IKustoCallRecord.Caller_CaptureDeviceDriver), "$.sessions[*].segments[*].media[*].callerDevice.captureDeviceDriver" }, + { nameof(IKustoCallRecord.Caller_RenderDeviceName), "$.sessions[*].segments[*].media[*].callerDevice.renderDeviceName" }, + { nameof(IKustoCallRecord.Caller_RenderDeviceDriver), "$.sessions[*].segments[*].media[*].callerDevice.renderDeviceDriver" }, + { nameof(IKustoCallRecord.Caller_SentSignalLevel), "$.sessions[*].segments[*].media[*].callerDevice.sentSignalLevel" }, + { nameof(IKustoCallRecord.Caller_SentNoiseLevel), "$.sessions[*].segments[*].media[*].callerDevice.sentNoiseLevel" }, + { nameof(IKustoCallRecord.Caller_MicGlitchRate), "$.sessions[*].segments[*].media[*].callerDevice.micGlitchRate" }, + { nameof(IKustoCallRecord.Caller_ReceivedSignalLevel), "$.sessions[*].segments[*].media[*].callerDevice.receivedSignalLevel" }, + { nameof(IKustoCallRecord.Caller_ReceivedNoiseLevel), "$.sessions[*].segments[*].media[*].callerDevice.receivedNoiseLevel" }, + { nameof(IKustoCallRecord.Caller_SpeakerGlitchRate), "$.sessions[*].segments[*].media[*].callerDevice.speakerGlitchRate" }, + { nameof(IKustoCallRecord.Caller_HowlingEventCount), "$.sessions[*].segments[*].media[*].callerDevice.howlingEventCount" }, + { nameof(IKustoCallRecord.Caller_InitialSignalLevelRootMeanSquare), "$.sessions[*].segments[*].media[*].callerDevice.initialSignalLevelRootMeanSquare" }, + { nameof(IKustoCallRecord.Caller_DeviceGlitchEventRatio), "$.sessions[*].segments[*].media[*].callerDevice.deviceGlitchEventRatio" }, + { nameof(IKustoCallRecord.Caller_DeviceClippingEventRatio), "$.sessions[*].segments[*].media[*].callerDevice.deviceClippingEventRatio" }, + { nameof(IKustoCallRecord.Caller_LowSpeechToNoiseEventRatio), "$.sessions[*].segments[*].media[*].callerDevice.lowSpeechToNoiseEventRatio" }, + { nameof(IKustoCallRecord.Caller_CaptureNotFunctioningEventRatio), "$.sessions[*].segments[*].media[*].callerDevice.captureNotFunctioningEventRatio" }, + { nameof(IKustoCallRecord.Caller_SentQualityEventRatio), "$.sessions[*].segments[*].media[*].callerNetwork.sentQualityEventRatio" }, + { nameof(IKustoCallRecord.Caller_LowSpeechLevelEventRatio), "$.sessions[*].segments[*].media[*].callerDevice.lowSpeechLevelEventRatio" }, + { nameof(IKustoCallRecord.Caller_RenderNotFunctioningEventRatio), "$.sessions[*].segments[*].media[*].callerDevice.renderNotFunctioningEventRatio" }, + { nameof(IKustoCallRecord.Caller_ReceivedQualityEventRatio), "$.sessions[*].segments[*].media[*].callerNetwork.receivedQualityEventRatio" }, + { nameof(IKustoCallRecord.Caller_RenderZeroVolumeEventRatio), "$.sessions[*].segments[*].media[*].callerDevice.renderZeroVolumeEventRatio" }, + { nameof(IKustoCallRecord.Caller_RenderMuteEventRatio), "$.sessions[*].segments[*].media[*].callerDevice.renderMuteEventRatio" }, + { nameof(IKustoCallRecord.Caller_CpuInsufficentEventRatio), "$.sessions[*].segments[*].media[*].callerDevice.cpuInsufficentEventRatio" }, + { nameof(IKustoCallRecord.Caller_DelayEventRatio), "$.sessions[*].segments[*].media[*].callerNetwork.delayEventRatio" }, + { nameof(IKustoCallRecord.Caller_BandwidthLowEventRatio), "$.sessions[*].segments[*].media[*].callerNetwork.bandwidthLowEventRatio" }, + { nameof(IKustoCallRecord.Caller_FeedbackRating), "$.sessions[*].segments[*].caller.feedback.rating" }, + { nameof(IKustoCallRecord.Caller_FeedbackText), "$.sessions[*].segments[*].caller.feedback.text" }, + { nameof(IKustoCallRecord.Caller_FeedbackTokens), "$.sessions[*].segments[*].caller.feedback.tokens" }, + } + }, + shouldValidate: false); + + /// + /// Creates a new instance of from a JSON dictionary. + /// + /// + /// + private static IKustoCallRecord FromJsonDictionary(IDictionary jsonNodeDictionary) + { + return new KustoCallRecord + { + CallId = jsonNodeDictionary[nameof(IKustoCallRecord.CallId)] is JsonValue callIdJson && callIdJson.TryGetValue(out Guid? callId) ? callId : null, + SessionId = jsonNodeDictionary[nameof(IKustoCallRecord.SessionId)] is JsonValue sessionIdJson && sessionIdJson.TryGetValue(out Guid? sessionId) ? sessionId : null, + StreamId = jsonNodeDictionary[nameof(IKustoCallRecord.StreamId)] is JsonValue streamIdJson && streamIdJson.TryGetValue(out string? streamId) ? streamId : null, + StreamDirection = jsonNodeDictionary[nameof(IKustoCallRecord.StreamDirection)] is JsonValue streamDirectionJson && streamDirectionJson.TryGetValue(out string? streamDirection) ? streamDirection : null, + MediaLabel = jsonNodeDictionary[nameof(IKustoCallRecord.MediaLabel)] is JsonValue mediaLabelJson && mediaLabelJson.TryGetValue(out string? mediaLabel) ? mediaLabel : null, + CallStartTime = jsonNodeDictionary[nameof(IKustoCallRecord.CallStartTime)] is JsonValue callStartTimeJson && callStartTimeJson.TryGetValue(out DateTimeOffset? callStartTime) ? callStartTime : null, + CallEndTime = jsonNodeDictionary[nameof(IKustoCallRecord.CallEndTime)] is JsonValue callEndTimeJson && callEndTimeJson.TryGetValue(out DateTimeOffset? callEndTime) ? callEndTime : null, + SessionStartTime = jsonNodeDictionary[nameof(IKustoCallRecord.SessionStartTime)] is JsonValue sessionStartTimeJson && sessionStartTimeJson.TryGetValue(out DateTimeOffset? sessionStartTime) ? sessionStartTime : null, + SessionEndTime = jsonNodeDictionary[nameof(IKustoCallRecord.SessionEndTime)] is JsonValue sessionEndTimeJson && sessionEndTimeJson.TryGetValue(out DateTimeOffset? sessionEndTime) ? sessionEndTime : null, + LastModifiedDateTimeOffset = jsonNodeDictionary[nameof(IKustoCallRecord.LastModifiedDateTimeOffset)] is JsonValue lastModifiedDateTimeOffsetJson && lastModifiedDateTimeOffsetJson.TryGetValue(out DateTimeOffset? lastModifiedDateTimeOffset) ? lastModifiedDateTimeOffset : null, + CallType = jsonNodeDictionary[nameof(IKustoCallRecord.CallType)] is JsonValue callTypeJson && callTypeJson.TryGetValue(out string? callType) ? callType : null, + JoinWebUrl = jsonNodeDictionary[nameof(IKustoCallRecord.JoinWebUrl)] is JsonValue joinWebUrlJson && joinWebUrlJson.TryGetValue(out string? joinWebUrl) ? joinWebUrl : null, + VideoCodec = jsonNodeDictionary[nameof(IKustoCallRecord.VideoCodec)] is JsonValue videoCodecJson && videoCodecJson.TryGetValue(out string? videoCodec) ? videoCodec : null, + AudioCodec = jsonNodeDictionary[nameof(IKustoCallRecord.AudioCodec)] is JsonValue audioCodecJson && audioCodecJson.TryGetValue(out string? audioCodec) ? audioCodec : null, + WasMediaBypassed = jsonNodeDictionary[nameof(IKustoCallRecord.WasMediaBypassed)] is JsonValue wasMediaBypassedJson && wasMediaBypassedJson.TryGetValue(out bool? wasMediaBypassed) ? wasMediaBypassed : null, + FailureStage = jsonNodeDictionary[nameof(IKustoCallRecord.FailureStage)] is JsonValue failureStageJson && failureStageJson.TryGetValue(out string? failureStage) ? failureStage : null, + FailureReason = jsonNodeDictionary[nameof(IKustoCallRecord.FailureReason)] is JsonValue failureReasonJson && failureReasonJson.TryGetValue(out string? failureReason) ? failureReason : null, + PacketUtilization = jsonNodeDictionary[nameof(IKustoCallRecord.PacketUtilization)] is JsonValue packetUtilizationJson && packetUtilizationJson.TryGetValue(out long? packetUtilization) ? packetUtilization : null, + AverageBandwidthEstimate = jsonNodeDictionary[nameof(IKustoCallRecord.AverageBandwidthEstimate)] is JsonValue averageBandwidthEstimateJson && averageBandwidthEstimateJson.TryGetValue(out long? averageBandwidthEstimate) ? averageBandwidthEstimate : null, + AverageJitter = jsonNodeDictionary[nameof(IKustoCallRecord.AverageJitter)]?.GetValueAsTimeSpan(), + MaxJitter = jsonNodeDictionary[nameof(IKustoCallRecord.MaxJitter)]?.GetValueAsTimeSpan(), + AverageRoundTripTime = jsonNodeDictionary[nameof(IKustoCallRecord.AverageRoundTripTime)]?.GetValueAsTimeSpan(), + MaxRoundTripTime = jsonNodeDictionary[nameof(IKustoCallRecord.MaxRoundTripTime)]?.GetValueAsTimeSpan(), + AverageAudioNetworkJitter = jsonNodeDictionary[nameof(IKustoCallRecord.AverageAudioNetworkJitter)]?.GetValueAsTimeSpan(), + MaxAudioNetworkJitter = jsonNodeDictionary[nameof(IKustoCallRecord.MaxAudioNetworkJitter)]?.GetValueAsTimeSpan(), + AverageAudioDegradation = jsonNodeDictionary[nameof(IKustoCallRecord.AverageAudioDegradation)] is JsonValue averageAudioDegradationJson && averageAudioDegradationJson.TryGetValue(out double? averageAudioDegradation) ? averageAudioDegradation : null, + AveragePacketLossRate = jsonNodeDictionary[nameof(IKustoCallRecord.AveragePacketLossRate)] is JsonValue averagePacketLossRateJson && averagePacketLossRateJson.TryGetValue(out double? averagePacketLossRate) ? averagePacketLossRate : null, + MaxPacketLossRate = jsonNodeDictionary[nameof(IKustoCallRecord.MaxPacketLossRate)] is JsonValue maxPacketLossRateJson && maxPacketLossRateJson.TryGetValue(out double? maxPacketLossRate) ? maxPacketLossRate : null, + PostForwardErrorCorrectionPacketLossRate = jsonNodeDictionary[nameof(IKustoCallRecord.PostForwardErrorCorrectionPacketLossRate)] is JsonValue postForwardErrorCorrectionPacketLossRateJson && postForwardErrorCorrectionPacketLossRateJson.TryGetValue(out double? postForwardErrorCorrectionPacketLossRate) ? postForwardErrorCorrectionPacketLossRate : null, + AverageRatioOfConcealedSamples = jsonNodeDictionary[nameof(IKustoCallRecord.AverageRatioOfConcealedSamples)] is JsonValue averageRatioOfConcealedSamplesJson && averageRatioOfConcealedSamplesJson.TryGetValue(out double? averageRatioOfConcealedSamples) ? averageRatioOfConcealedSamples : null, + MaxRatioOfConcealedSamples = jsonNodeDictionary[nameof(IKustoCallRecord.MaxRatioOfConcealedSamples)] is JsonValue maxRatioOfConcealedSamplesJson && maxRatioOfConcealedSamplesJson.TryGetValue(out double? maxRatioOfConcealedSamples) ? maxRatioOfConcealedSamples : null, + LowVideoProcessingCapabilityRatio = jsonNodeDictionary[nameof(IKustoCallRecord.LowVideoProcessingCapabilityRatio)] is JsonValue lowVideoProcessingCapabilityRatioJson && lowVideoProcessingCapabilityRatioJson.TryGetValue(out double? lowVideoProcessingCapabilityRatio) ? lowVideoProcessingCapabilityRatio : null, + AverageVideoFrameRate = jsonNodeDictionary[nameof(IKustoCallRecord.AverageVideoFrameRate)] is JsonValue averageVideoFrameRateJson && averageVideoFrameRateJson.TryGetValue(out double? averageVideoFrameRate) ? averageVideoFrameRate : null, + AverageReceivedFrameRate = jsonNodeDictionary[nameof(IKustoCallRecord.AverageReceivedFrameRate)] is JsonValue averageReceivedFrameRateJson && averageReceivedFrameRateJson.TryGetValue(out double? averageReceivedFrameRate) ? averageReceivedFrameRate : null, + LowFrameRateRatio = jsonNodeDictionary[nameof(IKustoCallRecord.LowFrameRateRatio)] is JsonValue lowFrameRateRatioJson && lowFrameRateRatioJson.TryGetValue(out double? lowFrameRateRatio) ? lowFrameRateRatio : null, + AverageVideoPacketLossRate = jsonNodeDictionary[nameof(IKustoCallRecord.AverageVideoPacketLossRate)] is JsonValue averageVideoPacketLossRateJson && averageVideoPacketLossRateJson.TryGetValue(out double? averageVideoPacketLossRate) ? averageVideoPacketLossRate : null, + AverageVideoFrameLossPercentage = jsonNodeDictionary[nameof(IKustoCallRecord.AverageVideoFrameLossPercentage)] is JsonValue averageVideoFrameLossPercentageJson && averageVideoFrameLossPercentageJson.TryGetValue(out double? averageVideoFrameLossPercentage) ? averageVideoFrameLossPercentage : null, + Organizer_UserDisplayName = jsonNodeDictionary[nameof(IKustoCallRecord.Organizer_UserDisplayName)] is JsonValue organizer_UserDisplayNameJson && organizer_UserDisplayNameJson.TryGetValue(out string? organizer_UserDisplayName) ? organizer_UserDisplayName : null, + Organizer_UserId = jsonNodeDictionary[nameof(IKustoCallRecord.Organizer_UserId)] is JsonValue organizer_UserIdJson && organizer_UserIdJson.TryGetValue(out Guid? organizer_UserId) ? organizer_UserId : null, + Organizer_UserTenantId = jsonNodeDictionary[nameof(IKustoCallRecord.Organizer_UserTenantId)] is JsonValue organizer_UserTenantIdJson && organizer_UserTenantIdJson.TryGetValue(out Guid? organizer_UserTenantId) ? organizer_UserTenantId : null, + Organizer_ApplicationInstanceDisplayName = jsonNodeDictionary[nameof(IKustoCallRecord.Organizer_ApplicationInstanceDisplayName)] is JsonValue organizer_ApplicationInstanceDisplayNameJson && organizer_ApplicationInstanceDisplayNameJson.TryGetValue(out string? organizer_ApplicationInstanceDisplayName) ? organizer_ApplicationInstanceDisplayName : null, + Organizer_ApplicationInstanceId = jsonNodeDictionary[nameof(IKustoCallRecord.Organizer_ApplicationInstanceId)] is JsonValue organizer_ApplicationInstanceIdJson && organizer_ApplicationInstanceIdJson.TryGetValue(out Guid? organizer_ApplicationInstanceId) ? organizer_ApplicationInstanceId : null, + Organizer_ApplicationInstanceTenantId = jsonNodeDictionary[nameof(IKustoCallRecord.Organizer_ApplicationInstanceTenantId)] is JsonValue organizer_ApplicationInstanceTenantIdJson && organizer_ApplicationInstanceTenantIdJson.TryGetValue(out Guid? organizer_ApplicationInstanceTenantId) ? organizer_ApplicationInstanceTenantId : null, + Organizer_GuestDisplayName = jsonNodeDictionary[nameof(IKustoCallRecord.Organizer_GuestDisplayName)] is JsonValue organizer_GuestDisplayNameJson && organizer_GuestDisplayNameJson.TryGetValue(out string? organizer_GuestDisplayName) ? organizer_GuestDisplayName : null, + Organizer_GuestId = jsonNodeDictionary[nameof(IKustoCallRecord.Organizer_GuestId)] is JsonValue organizer_GuestIdJson && organizer_GuestIdJson.TryGetValue(out Guid? organizer_GuestId) ? organizer_GuestId : null, + Organizer_GuestTenantId = jsonNodeDictionary[nameof(IKustoCallRecord.Organizer_GuestTenantId)] is JsonValue organizer_GuestTenantIdJson && organizer_GuestTenantIdJson.TryGetValue(out Guid? organizer_GuestTenantId) ? organizer_GuestTenantId : null, + Organizer_PhoneDisplayName = jsonNodeDictionary[nameof(IKustoCallRecord.Organizer_PhoneDisplayName)] is JsonValue organizer_PhoneDisplayNameJson && organizer_PhoneDisplayNameJson.TryGetValue(out string? organizer_PhoneDisplayName) ? organizer_PhoneDisplayName : null, + Organizer_PhoneId = jsonNodeDictionary[nameof(IKustoCallRecord.Organizer_PhoneId)] is JsonValue organizer_PhoneIdJson && organizer_PhoneIdJson.TryGetValue(out string? organizer_PhoneId) ? organizer_PhoneId : null, + Organizer_PhoneTenantId = jsonNodeDictionary[nameof(IKustoCallRecord.Organizer_PhoneTenantId)] is JsonValue organizer_PhoneTenantIdJson && organizer_PhoneTenantIdJson.TryGetValue(out Guid? organizer_PhoneTenantId) ? organizer_PhoneTenantId : null, + Organizer_OnPremisesDisplayName = jsonNodeDictionary[nameof(IKustoCallRecord.Organizer_OnPremisesDisplayName)] is JsonValue organizer_OnPremisesDisplayNameJson && organizer_OnPremisesDisplayNameJson.TryGetValue(out string? organizer_OnPremisesDisplayName) ? organizer_OnPremisesDisplayName : null, + Organizer_OnPremisesId = jsonNodeDictionary[nameof(IKustoCallRecord.Organizer_OnPremisesId)] is JsonValue organizer_OnPremisesIdJson && organizer_OnPremisesIdJson.TryGetValue(out Guid? organizer_OnPremisesId) ? organizer_OnPremisesId : null, + Organizer_OnPremisesTenantId = jsonNodeDictionary[nameof(IKustoCallRecord.Organizer_OnPremisesTenantId)] is JsonValue organizer_OnPremisesTenantIdJson && organizer_OnPremisesTenantIdJson.TryGetValue(out Guid? organizer_OnPremisesTenantId) ? organizer_OnPremisesTenantId : null, + Organizer_EncryptedDisplayName = jsonNodeDictionary[nameof(IKustoCallRecord.Organizer_EncryptedDisplayName)] is JsonValue organizer_EncryptedDisplayNameJson && organizer_EncryptedDisplayNameJson.TryGetValue(out string? organizer_EncryptedDisplayName) ? organizer_EncryptedDisplayName : null, + Organizer_EncryptedId = jsonNodeDictionary[nameof(IKustoCallRecord.Organizer_EncryptedId)] is JsonValue organizer_EncryptedIdJson && organizer_EncryptedIdJson.TryGetValue(out Guid? organizer_EncryptedId) ? organizer_EncryptedId : null, + Organizer_EncryptedTenantId = jsonNodeDictionary[nameof(IKustoCallRecord.Organizer_EncryptedTenantId)] is JsonValue organizer_EncryptedTenantIdJson && organizer_EncryptedTenantIdJson.TryGetValue(out Guid? organizer_EncryptedTenantId) ? organizer_EncryptedTenantId : null, + Organizer_AcsUserDisplayName = jsonNodeDictionary[nameof(IKustoCallRecord.Organizer_AcsUserDisplayName)] is JsonValue organizer_AcsUserDisplayNameJson && organizer_AcsUserDisplayNameJson.TryGetValue(out string? organizer_AcsUserDisplayName) ? organizer_AcsUserDisplayName : null, + Organizer_AcsUserId = jsonNodeDictionary[nameof(IKustoCallRecord.Organizer_AcsUserId)] is JsonValue organizer_AcsUserIdJson && organizer_AcsUserIdJson.TryGetValue(out Guid? organizer_AcsUserId) ? organizer_AcsUserId : null, + Organizer_AcsUserTenantId = jsonNodeDictionary[nameof(IKustoCallRecord.Organizer_AcsUserTenantId)] is JsonValue organizer_AcsUserTenantIdJson && organizer_AcsUserTenantIdJson.TryGetValue(out Guid? organizer_AcsUserTenantId) ? organizer_AcsUserTenantId : null, + Organizer_SpoolUserDisplayName = jsonNodeDictionary[nameof(IKustoCallRecord.Organizer_SpoolUserDisplayName)] is JsonValue organizer_SpoolUserDisplayNameJson && organizer_SpoolUserDisplayNameJson.TryGetValue(out string? organizer_SpoolUserDisplayName) ? organizer_SpoolUserDisplayName : null, + Organizer_SpoolUserId = jsonNodeDictionary[nameof(IKustoCallRecord.Organizer_SpoolUserId)] is JsonValue organizer_SpoolUserIdJson && organizer_SpoolUserIdJson.TryGetValue(out Guid? organizer_SpoolUserId) ? organizer_SpoolUserId : null, + Organizer_SpoolUserTenantId = jsonNodeDictionary[nameof(IKustoCallRecord.Organizer_SpoolUserTenantId)] is JsonValue organizer_SpoolUserTenantIdJson && organizer_SpoolUserTenantIdJson.TryGetValue(out Guid? organizer_SpoolUserTenantId) ? organizer_SpoolUserTenantId : null, + Organizer_AcsApplicationInstanceDisplayName = jsonNodeDictionary[nameof(IKustoCallRecord.Organizer_AcsApplicationInstanceDisplayName)] is JsonValue organizer_AcsApplicationInstanceDisplayNameJson && organizer_AcsApplicationInstanceDisplayNameJson.TryGetValue(out string? organizer_AcsApplicationInstanceDisplayName) ? organizer_AcsApplicationInstanceDisplayName : null, + Organizer_AcsApplicationInstanceId = jsonNodeDictionary[nameof(IKustoCallRecord.Organizer_AcsApplicationInstanceId)] is JsonValue organizer_AcsApplicationInstanceIdJson && organizer_AcsApplicationInstanceIdJson.TryGetValue(out Guid? organizer_AcsApplicationInstanceId) ? organizer_AcsApplicationInstanceId : null, + Organizer_AcsApplicationInstanceTenantId = jsonNodeDictionary[nameof(IKustoCallRecord.Organizer_AcsApplicationInstanceTenantId)] is JsonValue organizer_AcsApplicationInstanceTenantIdJson && organizer_AcsApplicationInstanceTenantIdJson.TryGetValue(out Guid? organizer_AcsApplicationInstanceTenantId) ? organizer_AcsApplicationInstanceTenantId : null, + Organizer_SpoolApplicationInstanceDisplayName = jsonNodeDictionary[nameof(IKustoCallRecord.Organizer_SpoolApplicationInstanceDisplayName)] is JsonValue organizer_SpoolApplicationInstanceDisplayNameJson && organizer_SpoolApplicationInstanceDisplayNameJson.TryGetValue(out string? organizer_SpoolApplicationInstanceDisplayName) ? organizer_SpoolApplicationInstanceDisplayName : null, + Organizer_SpoolApplicationInstanceId = jsonNodeDictionary[nameof(IKustoCallRecord.Organizer_SpoolApplicationInstanceId)] is JsonValue organizer_SpoolApplicationInstanceIdJson && organizer_SpoolApplicationInstanceIdJson.TryGetValue(out Guid? organizer_SpoolApplicationInstanceId) ? organizer_SpoolApplicationInstanceId : null, + Organizer_SpoolApplicationInstanceTenantId = jsonNodeDictionary[nameof(IKustoCallRecord.Organizer_SpoolApplicationInstanceTenantId)] is JsonValue organizer_SpoolApplicationInstanceTenantIdJson && organizer_SpoolApplicationInstanceTenantIdJson.TryGetValue(out Guid? organizer_SpoolApplicationInstanceTenantId) ? organizer_SpoolApplicationInstanceTenantId : null, + Callee_UserDisplayName = jsonNodeDictionary[nameof(IKustoCallRecord.Callee_UserDisplayName)] is JsonValue callee_UserDisplayNameJson && callee_UserDisplayNameJson.TryGetValue(out string? callee_UserDisplayName) ? callee_UserDisplayName : null, + Callee_UserId = jsonNodeDictionary[nameof(IKustoCallRecord.Callee_UserId)] is JsonValue callee_UserIdJson && callee_UserIdJson.TryGetValue(out Guid? callee_UserId) ? callee_UserId : null, + Callee_UserTenantId = jsonNodeDictionary[nameof(IKustoCallRecord.Callee_UserTenantId)] is JsonValue callee_UserTenantIdJson && callee_UserTenantIdJson.TryGetValue(out Guid? callee_UserTenantId) ? callee_UserTenantId : null, + Callee_ApplicationInstanceDisplayName = jsonNodeDictionary[nameof(IKustoCallRecord.Callee_ApplicationInstanceDisplayName)] is JsonValue callee_ApplicationInstanceDisplayNameJson && callee_ApplicationInstanceDisplayNameJson.TryGetValue(out string? callee_ApplicationInstanceDisplayName) ? callee_ApplicationInstanceDisplayName : null, + Callee_ApplicationInstanceId = jsonNodeDictionary[nameof(IKustoCallRecord.Callee_ApplicationInstanceId)] is JsonValue callee_ApplicationInstanceIdJson && callee_ApplicationInstanceIdJson.TryGetValue(out Guid? callee_ApplicationInstanceId) ? callee_ApplicationInstanceId : null, + Callee_ApplicationInstanceTenantId = jsonNodeDictionary[nameof(IKustoCallRecord.Callee_ApplicationInstanceTenantId)] is JsonValue callee_ApplicationInstanceTenantIdJson && callee_ApplicationInstanceTenantIdJson.TryGetValue(out Guid? callee_ApplicationInstanceTenantId) ? callee_ApplicationInstanceTenantId : null, + Callee_GuestDisplayName = jsonNodeDictionary[nameof(IKustoCallRecord.Callee_GuestDisplayName)] is JsonValue callee_GuestDisplayNameJson && callee_GuestDisplayNameJson.TryGetValue(out string? callee_GuestDisplayName) ? callee_GuestDisplayName : null, + Callee_GuestId = jsonNodeDictionary[nameof(IKustoCallRecord.Callee_GuestId)] is JsonValue callee_GuestIdJson && callee_GuestIdJson.TryGetValue(out Guid? callee_GuestId) ? callee_GuestId : null, + Callee_GuestTenantId = jsonNodeDictionary[nameof(IKustoCallRecord.Callee_GuestTenantId)] is JsonValue callee_GuestTenantIdJson && callee_GuestTenantIdJson.TryGetValue(out Guid? callee_GuestTenantId) ? callee_GuestTenantId : null, + Callee_PhoneDisplayName = jsonNodeDictionary[nameof(IKustoCallRecord.Callee_PhoneDisplayName)] is JsonValue callee_PhoneDisplayNameJson && callee_PhoneDisplayNameJson.TryGetValue(out string? callee_PhoneDisplayName) ? callee_PhoneDisplayName : null, + Callee_PhoneId = jsonNodeDictionary[nameof(IKustoCallRecord.Callee_PhoneId)] is JsonValue callee_PhoneIdJson && callee_PhoneIdJson.TryGetValue(out string? callee_PhoneId) ? callee_PhoneId : null, + Callee_PhoneTenantId = jsonNodeDictionary[nameof(IKustoCallRecord.Callee_PhoneTenantId)] is JsonValue callee_PhoneTenantIdJson && callee_PhoneTenantIdJson.TryGetValue(out Guid? callee_PhoneTenantId) ? callee_PhoneTenantId : null, + Callee_OnPremisesDisplayName = jsonNodeDictionary[nameof(IKustoCallRecord.Callee_OnPremisesDisplayName)] is JsonValue callee_OnPremisesDisplayNameJson && callee_OnPremisesDisplayNameJson.TryGetValue(out string? callee_OnPremisesDisplayName) ? callee_OnPremisesDisplayName : null, + Callee_OnPremisesId = jsonNodeDictionary[nameof(IKustoCallRecord.Callee_OnPremisesId)] is JsonValue callee_OnPremisesIdJson && callee_OnPremisesIdJson.TryGetValue(out Guid? callee_OnPremisesId) ? callee_OnPremisesId : null, + Callee_OnPremisesTenantId = jsonNodeDictionary[nameof(IKustoCallRecord.Callee_OnPremisesTenantId)] is JsonValue callee_OnPremisesTenantIdJson && callee_OnPremisesTenantIdJson.TryGetValue(out Guid? callee_OnPremisesTenantId) ? callee_OnPremisesTenantId : null, + Callee_EncryptedDisplayName = jsonNodeDictionary[nameof(IKustoCallRecord.Callee_EncryptedDisplayName)] is JsonValue callee_EncryptedDisplayNameJson && callee_EncryptedDisplayNameJson.TryGetValue(out string? callee_EncryptedDisplayName) ? callee_EncryptedDisplayName : null, + Callee_EncryptedId = jsonNodeDictionary[nameof(IKustoCallRecord.Callee_EncryptedId)] is JsonValue callee_EncryptedIdJson && callee_EncryptedIdJson.TryGetValue(out Guid? callee_EncryptedId) ? callee_EncryptedId : null, + Callee_EncryptedTenantId = jsonNodeDictionary[nameof(IKustoCallRecord.Callee_EncryptedTenantId)] is JsonValue callee_EncryptedTenantIdJson && callee_EncryptedTenantIdJson.TryGetValue(out Guid? callee_EncryptedTenantId) ? callee_EncryptedTenantId : null, + Callee_AcsUserDisplayName = jsonNodeDictionary[nameof(IKustoCallRecord.Callee_AcsUserDisplayName)] is JsonValue callee_AcsUserDisplayNameJson && callee_AcsUserDisplayNameJson.TryGetValue(out string? callee_AcsUserDisplayName) ? callee_AcsUserDisplayName : null, + Callee_AcsUserId = jsonNodeDictionary[nameof(IKustoCallRecord.Callee_AcsUserId)] is JsonValue callee_AcsUserIdJson && callee_AcsUserIdJson.TryGetValue(out Guid? callee_AcsUserId) ? callee_AcsUserId : null, + Callee_AcsUserTenantId = jsonNodeDictionary[nameof(IKustoCallRecord.Callee_AcsUserTenantId)] is JsonValue callee_AcsUserTenantIdJson && callee_AcsUserTenantIdJson.TryGetValue(out Guid? callee_AcsUserTenantId) ? callee_AcsUserTenantId : null, + Callee_SpoolUserDisplayName = jsonNodeDictionary[nameof(IKustoCallRecord.Callee_SpoolUserDisplayName)] is JsonValue callee_SpoolUserDisplayNameJson && callee_SpoolUserDisplayNameJson.TryGetValue(out string? callee_SpoolUserDisplayName) ? callee_SpoolUserDisplayName : null, + Callee_SpoolUserId = jsonNodeDictionary[nameof(IKustoCallRecord.Callee_SpoolUserId)] is JsonValue callee_SpoolUserIdJson && callee_SpoolUserIdJson.TryGetValue(out Guid? callee_SpoolUserId) ? callee_SpoolUserId : null, + Callee_SpoolUserTenantId = jsonNodeDictionary[nameof(IKustoCallRecord.Callee_SpoolUserTenantId)] is JsonValue callee_SpoolUserTenantIdJson && callee_SpoolUserTenantIdJson.TryGetValue(out Guid? callee_SpoolUserTenantId) ? callee_SpoolUserTenantId : null, + Callee_AcsApplicationInstanceDisplayName = jsonNodeDictionary[nameof(IKustoCallRecord.Callee_AcsApplicationInstanceDisplayName)] is JsonValue callee_AcsApplicationInstanceDisplayNameJson && callee_AcsApplicationInstanceDisplayNameJson.TryGetValue(out string? callee_AcsApplicationInstanceDisplayName) ? callee_AcsApplicationInstanceDisplayName : null, + Callee_AcsApplicationInstanceId = jsonNodeDictionary[nameof(IKustoCallRecord.Callee_AcsApplicationInstanceId)] is JsonValue callee_AcsApplicationInstanceIdJson && callee_AcsApplicationInstanceIdJson.TryGetValue(out Guid? callee_AcsApplicationInstanceId) ? callee_AcsApplicationInstanceId : null, + Callee_AcsApplicationInstanceTenantId = jsonNodeDictionary[nameof(IKustoCallRecord.Callee_AcsApplicationInstanceTenantId)] is JsonValue callee_AcsApplicationInstanceTenantIdJson && callee_AcsApplicationInstanceTenantIdJson.TryGetValue(out Guid? callee_AcsApplicationInstanceTenantId) ? callee_AcsApplicationInstanceTenantId : null, + Callee_SpoolApplicationInstanceDisplayName = jsonNodeDictionary[nameof(IKustoCallRecord.Callee_SpoolApplicationInstanceDisplayName)] is JsonValue callee_SpoolApplicationInstanceDisplayNameJson && callee_SpoolApplicationInstanceDisplayNameJson.TryGetValue(out string? callee_SpoolApplicationInstanceDisplayName) ? callee_SpoolApplicationInstanceDisplayName : null, + Callee_SpoolApplicationInstanceId = jsonNodeDictionary[nameof(IKustoCallRecord.Callee_SpoolApplicationInstanceId)] is JsonValue callee_SpoolApplicationInstanceIdJson && callee_SpoolApplicationInstanceIdJson.TryGetValue(out Guid? callee_SpoolApplicationInstanceId) ? callee_SpoolApplicationInstanceId : null, + Callee_SpoolApplicationInstanceTenantId = jsonNodeDictionary[nameof(IKustoCallRecord.Callee_SpoolApplicationInstanceTenantId)] is JsonValue callee_SpoolApplicationInstanceTenantIdJson && callee_SpoolApplicationInstanceTenantIdJson.TryGetValue(out Guid? callee_SpoolApplicationInstanceTenantId) ? callee_SpoolApplicationInstanceTenantId : null, + Callee_EndpointType = jsonNodeDictionary[nameof(IKustoCallRecord.Callee_EndpointType)] is JsonValue callee_EndpointTypeJson && callee_EndpointTypeJson.TryGetValue(out string? callee_EndpointType) ? callee_EndpointType : null, + Callee_ProductFamily = jsonNodeDictionary[nameof(IKustoCallRecord.Callee_ProductFamily)] is JsonValue callee_ProductFamilyJson && callee_ProductFamilyJson.TryGetValue(out string? callee_ProductFamily) ? callee_ProductFamily : null, + Callee_Platform = jsonNodeDictionary[nameof(IKustoCallRecord.Callee_Platform)] is JsonValue callee_PlatformJson && callee_PlatformJson.TryGetValue(out string? callee_Platform) ? callee_Platform : null, + Callee_UserAgentHeaderValue = jsonNodeDictionary[nameof(IKustoCallRecord.Callee_UserAgentHeaderValue)] is JsonValue callee_UserAgentHeaderValueJson && callee_UserAgentHeaderValueJson.TryGetValue(out string? callee_UserAgentHeaderValue) ? callee_UserAgentHeaderValue : null, + Callee_ServiceRole = jsonNodeDictionary[nameof(IKustoCallRecord.Callee_ServiceRole)] is JsonValue callee_ServiceRoleJson && callee_ServiceRoleJson.TryGetValue(out string? callee_ServiceRole) ? callee_ServiceRole : null, + Callee_ApplicationVersion = jsonNodeDictionary[nameof(IKustoCallRecord.Callee_ApplicationVersion)] is JsonValue callee_ApplicationVersionJson && callee_ApplicationVersionJson.TryGetValue(out string? callee_ApplicationVersion) ? callee_ApplicationVersion : null, + Callee_AzureAdAppId = jsonNodeDictionary[nameof(IKustoCallRecord.Callee_AzureAdAppId)] is JsonValue callee_AzureAdAppIdJson && callee_AzureAdAppIdJson.TryGetValue(out Guid? callee_AzureAdAppId) ? callee_AzureAdAppId : null, + Callee_CommunicationServiceId = jsonNodeDictionary[nameof(IKustoCallRecord.Callee_CommunicationServiceId)] is JsonValue callee_CommunicationServiceIdJson && callee_CommunicationServiceIdJson.TryGetValue(out Guid? callee_CommunicationServiceId) ? callee_CommunicationServiceId : null, + Callee_ConnectionType = jsonNodeDictionary[nameof(IKustoCallRecord.Callee_ConnectionType)] is JsonValue callee_ConnectionTypeJson && callee_ConnectionTypeJson.TryGetValue(out string? callee_ConnectionType) ? callee_ConnectionType : null, + Callee_ReflexiveIPAddress = jsonNodeDictionary[nameof(IKustoCallRecord.Callee_ReflexiveIPAddress)] is JsonValue callee_ReflexiveIPAddressJson && callee_ReflexiveIPAddressJson.TryGetValue(out string? callee_ReflexiveIPAddress) ? callee_ReflexiveIPAddress : null, + Callee_Subnet = jsonNodeDictionary[nameof(IKustoCallRecord.Callee_Subnet)] is JsonValue callee_SubnetJson && callee_SubnetJson.TryGetValue(out string? callee_Subnet) ? callee_Subnet : null, + Callee_IpAddress = jsonNodeDictionary[nameof(IKustoCallRecord.Callee_IpAddress)] is JsonValue callee_IpAddressJson && callee_IpAddressJson.TryGetValue(out string? callee_IpAddress) ? callee_IpAddress : null, + Callee_MacAddress = jsonNodeDictionary[nameof(IKustoCallRecord.Callee_MacAddress)] is JsonValue callee_MacAddressJson && callee_MacAddressJson.TryGetValue(out string? callee_MacAddress) ? callee_MacAddress : null, + Callee_LinkSpeed = jsonNodeDictionary[nameof(IKustoCallRecord.Callee_LinkSpeed)] is JsonValue callee_LinkSpeedJson && callee_LinkSpeedJson.TryGetValue(out long? callee_LinkSpeed) ? callee_LinkSpeed : null, + Callee_NetworkTransportProtocol = jsonNodeDictionary[nameof(IKustoCallRecord.Callee_NetworkTransportProtocol)] is JsonValue callee_NetworkTransportProtocolJson && callee_NetworkTransportProtocolJson.TryGetValue(out string? callee_NetworkTransportProtocol) ? callee_NetworkTransportProtocol : null, + Callee_Port = jsonNodeDictionary[nameof(IKustoCallRecord.Callee_Port)] is JsonValue callee_PortJson && callee_PortJson.TryGetValue(out int? callee_Port) ? callee_Port : null, + Callee_RelayIPAddress = jsonNodeDictionary[nameof(IKustoCallRecord.Callee_RelayIPAddress)] is JsonValue callee_RelayIPAddressJson && callee_RelayIPAddressJson.TryGetValue(out string? callee_RelayIPAddress) ? callee_RelayIPAddress : null, + Callee_RelayPort = jsonNodeDictionary[nameof(IKustoCallRecord.Callee_RelayPort)] is JsonValue callee_RelayPortJson && callee_RelayPortJson.TryGetValue(out int? callee_RelayPort) ? callee_RelayPort : null, + Callee_DnsSuffix = jsonNodeDictionary[nameof(IKustoCallRecord.Callee_DnsSuffix)] is JsonValue callee_DnsSuffixJson && callee_DnsSuffixJson.TryGetValue(out string? callee_DnsSuffix) ? callee_DnsSuffix : null, + Callee_TraceRouteHops = jsonNodeDictionary[nameof(IKustoCallRecord.Callee_TraceRouteHops)] is JsonValue callee_TraceRouteHopsJson && callee_TraceRouteHopsJson.TryGetValue(out string? callee_TraceRouteHops) ? callee_TraceRouteHops : null, + Callee_BSSID = jsonNodeDictionary[nameof(IKustoCallRecord.Callee_BSSID)] is JsonValue callee_BSSIDJson && callee_BSSIDJson.TryGetValue(out string? callee_BSSID) ? callee_BSSID : null, + Callee_WifiRadioType = jsonNodeDictionary[nameof(IKustoCallRecord.Callee_WifiRadioType)] is JsonValue callee_WifiRadioTypeJson && callee_WifiRadioTypeJson.TryGetValue(out string? callee_WifiRadioType) ? callee_WifiRadioType : null, + Callee_WifiBand = jsonNodeDictionary[nameof(IKustoCallRecord.Callee_WifiBand)] is JsonValue callee_WifiBandJson && callee_WifiBandJson.TryGetValue(out string? callee_WifiBand) ? callee_WifiBand : null, + Callee_WifiChannel = jsonNodeDictionary[nameof(IKustoCallRecord.Callee_WifiChannel)] is JsonValue callee_WifiChannelJson && callee_WifiChannelJson.TryGetValue(out int? callee_WifiChannel) ? callee_WifiChannel : null, + Callee_WifiSignalStrength = jsonNodeDictionary[nameof(IKustoCallRecord.Callee_WifiSignalStrength)] is JsonValue callee_WifiSignalStrengthJson && callee_WifiSignalStrengthJson.TryGetValue(out int? callee_WifiSignalStrength) ? callee_WifiSignalStrength : null, + Callee_WifiBatteryCharge = jsonNodeDictionary[nameof(IKustoCallRecord.Callee_WifiBatteryCharge)] is JsonValue callee_WifiBatteryChargeJson && callee_WifiBatteryChargeJson.TryGetValue(out int? callee_WifiBatteryCharge) ? callee_WifiBatteryCharge : null, + Callee_WifiMicrosoftDriver = jsonNodeDictionary[nameof(IKustoCallRecord.Callee_WifiMicrosoftDriver)] is JsonValue callee_WifiMicrosoftDriverJson && callee_WifiMicrosoftDriverJson.TryGetValue(out string? callee_WifiMicrosoftDriver) ? callee_WifiMicrosoftDriver : null, + Callee_WifiMicrosoftDriverVersion = jsonNodeDictionary[nameof(IKustoCallRecord.Callee_WifiMicrosoftDriverVersion)] is JsonValue callee_WifiMicrosoftDriverVersionJson && callee_WifiMicrosoftDriverVersionJson.TryGetValue(out string? callee_WifiMicrosoftDriverVersion) ? callee_WifiMicrosoftDriverVersion : null, + Callee_WifiVendorDriver = jsonNodeDictionary[nameof(IKustoCallRecord.Callee_WifiVendorDriver)] is JsonValue callee_WifiVendorDriverJson && callee_WifiVendorDriverJson.TryGetValue(out string? callee_WifiVendorDriver) ? callee_WifiVendorDriver : null, + Callee_WifiVendorDriverVersion = jsonNodeDictionary[nameof(IKustoCallRecord.Callee_WifiVendorDriverVersion)] is JsonValue callee_WifiVendorDriverVersionJson && callee_WifiVendorDriverVersionJson.TryGetValue(out string? callee_WifiVendorDriverVersion) ? callee_WifiVendorDriverVersion : null, + Callee_CaptureDeviceName = jsonNodeDictionary[nameof(IKustoCallRecord.Callee_CaptureDeviceName)] is JsonValue callee_CaptureDeviceNameJson && callee_CaptureDeviceNameJson.TryGetValue(out string? callee_CaptureDeviceName) ? callee_CaptureDeviceName : null, + Callee_CaptureDeviceDriver = jsonNodeDictionary[nameof(IKustoCallRecord.Callee_CaptureDeviceDriver)] is JsonValue callee_CaptureDeviceDriverJson && callee_CaptureDeviceDriverJson.TryGetValue(out string? callee_CaptureDeviceDriver) ? callee_CaptureDeviceDriver : null, + Callee_RenderDeviceName = jsonNodeDictionary[nameof(IKustoCallRecord.Callee_RenderDeviceName)] is JsonValue callee_RenderDeviceNameJson && callee_RenderDeviceNameJson.TryGetValue(out string? callee_RenderDeviceName) ? callee_RenderDeviceName : null, + Callee_RenderDeviceDriver = jsonNodeDictionary[nameof(IKustoCallRecord.Callee_RenderDeviceDriver)] is JsonValue callee_RenderDeviceDriverJson && callee_RenderDeviceDriverJson.TryGetValue(out string? callee_RenderDeviceDriver) ? callee_RenderDeviceDriver : null, + Callee_SentSignalLevel = jsonNodeDictionary[nameof(IKustoCallRecord.Callee_SentSignalLevel)] is JsonValue callee_SentSignalLevelJson && callee_SentSignalLevelJson.TryGetValue(out long? callee_SentSignalLevel) ? callee_SentSignalLevel : null, + Callee_SentNoiseLevel = jsonNodeDictionary[nameof(IKustoCallRecord.Callee_SentNoiseLevel)] is JsonValue callee_SentNoiseLevelJson && callee_SentNoiseLevelJson.TryGetValue(out long? callee_SentNoiseLevel) ? callee_SentNoiseLevel : null, + Callee_MicGlitchRate = jsonNodeDictionary[nameof(IKustoCallRecord.Callee_MicGlitchRate)] is JsonValue callee_MicGlitchRateJson && callee_MicGlitchRateJson.TryGetValue(out long? callee_MicGlitchRate) ? callee_MicGlitchRate : null, + Callee_ReceivedSignalLevel = jsonNodeDictionary[nameof(IKustoCallRecord.Callee_ReceivedSignalLevel)] is JsonValue callee_ReceivedSignalLevelJson && callee_ReceivedSignalLevelJson.TryGetValue(out long? callee_ReceivedSignalLevel) ? callee_ReceivedSignalLevel : null, + Callee_ReceivedNoiseLevel = jsonNodeDictionary[nameof(IKustoCallRecord.Callee_ReceivedNoiseLevel)] is JsonValue callee_ReceivedNoiseLevelJson && callee_ReceivedNoiseLevelJson.TryGetValue(out long? callee_ReceivedNoiseLevel) ? callee_ReceivedNoiseLevel : null, + Callee_SpeakerGlitchRate = jsonNodeDictionary[nameof(IKustoCallRecord.Callee_SpeakerGlitchRate)] is JsonValue callee_SpeakerGlitchRateJson && callee_SpeakerGlitchRateJson.TryGetValue(out long? callee_SpeakerGlitchRate) ? callee_SpeakerGlitchRate : null, + Callee_HowlingEventCount = jsonNodeDictionary[nameof(IKustoCallRecord.Callee_HowlingEventCount)] is JsonValue callee_HowlingEventCountJson && callee_HowlingEventCountJson.TryGetValue(out int? callee_HowlingEventCount) ? callee_HowlingEventCount : null, + Callee_InitialSignalLevelRootMeanSquare = jsonNodeDictionary[nameof(IKustoCallRecord.Callee_InitialSignalLevelRootMeanSquare)] is JsonValue callee_InitialSignalLevelRootMeanSquareJson && callee_InitialSignalLevelRootMeanSquareJson.TryGetValue(out long? callee_InitialSignalLevelRootMeanSquare) ? callee_InitialSignalLevelRootMeanSquare : null, + Callee_DeviceGlitchEventRatio = jsonNodeDictionary[nameof(IKustoCallRecord.Callee_DeviceGlitchEventRatio)] is JsonValue callee_DeviceGlitchEventRatioJson && callee_DeviceGlitchEventRatioJson.TryGetValue(out double? callee_DeviceGlitchEventRatio) ? callee_DeviceGlitchEventRatio : null, + Callee_DeviceClippingEventRatio = jsonNodeDictionary[nameof(IKustoCallRecord.Callee_DeviceClippingEventRatio)] is JsonValue callee_DeviceClippingEventRatioJson && callee_DeviceClippingEventRatioJson.TryGetValue(out double? callee_DeviceClippingEventRatio) ? callee_DeviceClippingEventRatio : null, + Callee_LowSpeechToNoiseEventRatio = jsonNodeDictionary[nameof(IKustoCallRecord.Callee_LowSpeechToNoiseEventRatio)] is JsonValue callee_LowSpeechToNoiseEventRatioJson && callee_LowSpeechToNoiseEventRatioJson.TryGetValue(out double? callee_LowSpeechToNoiseEventRatio) ? callee_LowSpeechToNoiseEventRatio : null, + Callee_CaptureNotFunctioningEventRatio = jsonNodeDictionary[nameof(IKustoCallRecord.Callee_CaptureNotFunctioningEventRatio)] is JsonValue callee_CaptureNotFunctioningEventRatioJson && callee_CaptureNotFunctioningEventRatioJson.TryGetValue(out double? callee_CaptureNotFunctioningEventRatio) ? callee_CaptureNotFunctioningEventRatio : null, + Callee_SentQualityEventRatio = jsonNodeDictionary[nameof(IKustoCallRecord.Callee_SentQualityEventRatio)] is JsonValue callee_SentQualityEventRatioJson && callee_SentQualityEventRatioJson.TryGetValue(out double? callee_SentQualityEventRatio) ? callee_SentQualityEventRatio : null, + Callee_LowSpeechLevelEventRatio = jsonNodeDictionary[nameof(IKustoCallRecord.Callee_LowSpeechLevelEventRatio)] is JsonValue callee_LowSpeechLevelEventRatioJson && callee_LowSpeechLevelEventRatioJson.TryGetValue(out double? callee_LowSpeechLevelEventRatio) ? callee_LowSpeechLevelEventRatio : null, + Callee_RenderNotFunctioningEventRatio = jsonNodeDictionary[nameof(IKustoCallRecord.Callee_RenderNotFunctioningEventRatio)] is JsonValue callee_RenderNotFunctioningEventRatioJson && callee_RenderNotFunctioningEventRatioJson.TryGetValue(out double? callee_RenderNotFunctioningEventRatio) ? callee_RenderNotFunctioningEventRatio : null, + Callee_ReceivedQualityEventRatio = jsonNodeDictionary[nameof(IKustoCallRecord.Callee_ReceivedQualityEventRatio)] is JsonValue callee_ReceivedQualityEventRatioJson && callee_ReceivedQualityEventRatioJson.TryGetValue(out double? callee_ReceivedQualityEventRatio) ? callee_ReceivedQualityEventRatio : null, + Callee_RenderZeroVolumeEventRatio = jsonNodeDictionary[nameof(IKustoCallRecord.Callee_RenderZeroVolumeEventRatio)] is JsonValue callee_RenderZeroVolumeEventRatioJson && callee_RenderZeroVolumeEventRatioJson.TryGetValue(out double? callee_RenderZeroVolumeEventRatio) ? callee_RenderZeroVolumeEventRatio : null, + Callee_RenderMuteEventRatio = jsonNodeDictionary[nameof(IKustoCallRecord.Callee_RenderMuteEventRatio)] is JsonValue callee_RenderMuteEventRatioJson && callee_RenderMuteEventRatioJson.TryGetValue(out double? callee_RenderMuteEventRatio) ? callee_RenderMuteEventRatio : null, + Callee_CpuInsufficentEventRatio = jsonNodeDictionary[nameof(IKustoCallRecord.Callee_CpuInsufficentEventRatio)] is JsonValue callee_CpuInsufficentEventRatioJson && callee_CpuInsufficentEventRatioJson.TryGetValue(out double? callee_CpuInsufficentEventRatio) ? callee_CpuInsufficentEventRatio : null, + Callee_DelayEventRatio = jsonNodeDictionary[nameof(IKustoCallRecord.Callee_DelayEventRatio)] is JsonValue callee_DelayEventRatioJson && callee_DelayEventRatioJson.TryGetValue(out double? callee_DelayEventRatio) ? callee_DelayEventRatio : null, + Callee_BandwidthLowEventRatio = jsonNodeDictionary[nameof(IKustoCallRecord.Callee_BandwidthLowEventRatio)] is JsonValue callee_BandwidthLowEventRatioJson && callee_BandwidthLowEventRatioJson.TryGetValue(out double? callee_BandwidthLowEventRatio) ? callee_BandwidthLowEventRatio : null, + Callee_FeedbackRating = jsonNodeDictionary[nameof(IKustoCallRecord.Callee_FeedbackRating)] is JsonValue callee_FeedbackRatingJson && callee_FeedbackRatingJson.TryGetValue(out string? callee_FeedbackRating) ? callee_FeedbackRating : null, + Callee_FeedbackText = jsonNodeDictionary[nameof(IKustoCallRecord.Callee_FeedbackText)] is JsonValue callee_FeedbackTextJson && callee_FeedbackTextJson.TryGetValue(out string? callee_FeedbackText) ? callee_FeedbackText : null, + Callee_FeedbackTokens = jsonNodeDictionary[nameof(IKustoCallRecord.Callee_FeedbackTokens)] is JsonValue callee_FeedbackTokensJson && callee_FeedbackTokensJson.TryGetValue(out string? callee_FeedbackTokens) ? callee_FeedbackTokens : null, + Caller_UserDisplayName = jsonNodeDictionary[nameof(IKustoCallRecord.Caller_UserDisplayName)] is JsonValue caller_UserDisplayNameJson && caller_UserDisplayNameJson.TryGetValue(out string? caller_UserDisplayName) ? caller_UserDisplayName : null, + Caller_UserId = jsonNodeDictionary[nameof(IKustoCallRecord.Caller_UserId)] is JsonValue caller_UserIdJson && caller_UserIdJson.TryGetValue(out Guid? caller_UserId) ? caller_UserId : null, + Caller_UserTenantId = jsonNodeDictionary[nameof(IKustoCallRecord.Caller_UserTenantId)] is JsonValue caller_UserTenantIdJson && caller_UserTenantIdJson.TryGetValue(out Guid? caller_UserTenantId) ? caller_UserTenantId : null, + Caller_ApplicationInstanceDisplayName = jsonNodeDictionary[nameof(IKustoCallRecord.Caller_ApplicationInstanceDisplayName)] is JsonValue caller_ApplicationInstanceDisplayNameJson && caller_ApplicationInstanceDisplayNameJson.TryGetValue(out string? caller_ApplicationInstanceDisplayName) ? caller_ApplicationInstanceDisplayName : null, + Caller_ApplicationInstanceId = jsonNodeDictionary[nameof(IKustoCallRecord.Caller_ApplicationInstanceId)] is JsonValue caller_ApplicationInstanceIdJson && caller_ApplicationInstanceIdJson.TryGetValue(out Guid? caller_ApplicationInstanceId) ? caller_ApplicationInstanceId : null, + Caller_ApplicationInstanceTenantId = jsonNodeDictionary[nameof(IKustoCallRecord.Caller_ApplicationInstanceTenantId)] is JsonValue caller_ApplicationInstanceTenantIdJson && caller_ApplicationInstanceTenantIdJson.TryGetValue(out Guid? caller_ApplicationInstanceTenantId) ? caller_ApplicationInstanceTenantId : null, + Caller_GuestDisplayName = jsonNodeDictionary[nameof(IKustoCallRecord.Caller_GuestDisplayName)] is JsonValue caller_GuestDisplayNameJson && caller_GuestDisplayNameJson.TryGetValue(out string? caller_GuestDisplayName) ? caller_GuestDisplayName : null, + Caller_GuestId = jsonNodeDictionary[nameof(IKustoCallRecord.Caller_GuestId)] is JsonValue caller_GuestIdJson && caller_GuestIdJson.TryGetValue(out Guid? caller_GuestId) ? caller_GuestId : null, + Caller_GuestTenantId = jsonNodeDictionary[nameof(IKustoCallRecord.Caller_GuestTenantId)] is JsonValue caller_GuestTenantIdJson && caller_GuestTenantIdJson.TryGetValue(out Guid? caller_GuestTenantId) ? caller_GuestTenantId : null, + Caller_PhoneDisplayName = jsonNodeDictionary[nameof(IKustoCallRecord.Caller_PhoneDisplayName)] is JsonValue caller_PhoneDisplayNameJson && caller_PhoneDisplayNameJson.TryGetValue(out string? caller_PhoneDisplayName) ? caller_PhoneDisplayName : null, + Caller_PhoneId = jsonNodeDictionary[nameof(IKustoCallRecord.Caller_PhoneId)] is JsonValue caller_PhoneIdJson && caller_PhoneIdJson.TryGetValue(out string? caller_PhoneId) ? caller_PhoneId : null, + Caller_PhoneTenantId = jsonNodeDictionary[nameof(IKustoCallRecord.Caller_PhoneTenantId)] is JsonValue caller_PhoneTenantIdJson && caller_PhoneTenantIdJson.TryGetValue(out Guid? caller_PhoneTenantId) ? caller_PhoneTenantId : null, + Caller_OnPremisesDisplayName = jsonNodeDictionary[nameof(IKustoCallRecord.Caller_OnPremisesDisplayName)] is JsonValue caller_OnPremisesDisplayNameJson && caller_OnPremisesDisplayNameJson.TryGetValue(out string? caller_OnPremisesDisplayName) ? caller_OnPremisesDisplayName : null, + Caller_OnPremisesId = jsonNodeDictionary[nameof(IKustoCallRecord.Caller_OnPremisesId)] is JsonValue caller_OnPremisesIdJson && caller_OnPremisesIdJson.TryGetValue(out Guid? caller_OnPremisesId) ? caller_OnPremisesId : null, + Caller_OnPremisesTenantId = jsonNodeDictionary[nameof(IKustoCallRecord.Caller_OnPremisesTenantId)] is JsonValue caller_OnPremisesTenantIdJson && caller_OnPremisesTenantIdJson.TryGetValue(out Guid? caller_OnPremisesTenantId) ? caller_OnPremisesTenantId : null, + Caller_EncryptedDisplayName = jsonNodeDictionary[nameof(IKustoCallRecord.Caller_EncryptedDisplayName)] is JsonValue caller_EncryptedDisplayNameJson && caller_EncryptedDisplayNameJson.TryGetValue(out string? caller_EncryptedDisplayName) ? caller_EncryptedDisplayName : null, + Caller_EncryptedId = jsonNodeDictionary[nameof(IKustoCallRecord.Caller_EncryptedId)] is JsonValue caller_EncryptedIdJson && caller_EncryptedIdJson.TryGetValue(out Guid? caller_EncryptedId) ? caller_EncryptedId : null, + Caller_EncryptedTenantId = jsonNodeDictionary[nameof(IKustoCallRecord.Caller_EncryptedTenantId)] is JsonValue caller_EncryptedTenantIdJson && caller_EncryptedTenantIdJson.TryGetValue(out Guid? caller_EncryptedTenantId) ? caller_EncryptedTenantId : null, + Caller_AcsUserDisplayName = jsonNodeDictionary[nameof(IKustoCallRecord.Caller_AcsUserDisplayName)] is JsonValue caller_AcsUserDisplayNameJson && caller_AcsUserDisplayNameJson.TryGetValue(out string? caller_AcsUserDisplayName) ? caller_AcsUserDisplayName : null, + Caller_AcsUserId = jsonNodeDictionary[nameof(IKustoCallRecord.Caller_AcsUserId)] is JsonValue caller_AcsUserIdJson && caller_AcsUserIdJson.TryGetValue(out Guid? caller_AcsUserId) ? caller_AcsUserId : null, + Caller_AcsUserTenantId = jsonNodeDictionary[nameof(IKustoCallRecord.Caller_AcsUserTenantId)] is JsonValue caller_AcsUserTenantIdJson && caller_AcsUserTenantIdJson.TryGetValue(out Guid? caller_AcsUserTenantId) ? caller_AcsUserTenantId : null, + Caller_SpoolUserDisplayName = jsonNodeDictionary[nameof(IKustoCallRecord.Caller_SpoolUserDisplayName)] is JsonValue caller_SpoolUserDisplayNameJson && caller_SpoolUserDisplayNameJson.TryGetValue(out string? caller_SpoolUserDisplayName) ? caller_SpoolUserDisplayName : null, + Caller_SpoolUserId = jsonNodeDictionary[nameof(IKustoCallRecord.Caller_SpoolUserId)] is JsonValue caller_SpoolUserIdJson && caller_SpoolUserIdJson.TryGetValue(out Guid? caller_SpoolUserId) ? caller_SpoolUserId : null, + Caller_SpoolUserTenantId = jsonNodeDictionary[nameof(IKustoCallRecord.Caller_SpoolUserTenantId)] is JsonValue caller_SpoolUserTenantIdJson && caller_SpoolUserTenantIdJson.TryGetValue(out Guid? caller_SpoolUserTenantId) ? caller_SpoolUserTenantId : null, + Caller_AcsApplicationInstanceDisplayName = jsonNodeDictionary[nameof(IKustoCallRecord.Caller_AcsApplicationInstanceDisplayName)] is JsonValue caller_AcsApplicationInstanceDisplayNameJson && caller_AcsApplicationInstanceDisplayNameJson.TryGetValue(out string? caller_AcsApplicationInstanceDisplayName) ? caller_AcsApplicationInstanceDisplayName : null, + Caller_AcsApplicationInstanceId = jsonNodeDictionary[nameof(IKustoCallRecord.Caller_AcsApplicationInstanceId)] is JsonValue caller_AcsApplicationInstanceIdJson && caller_AcsApplicationInstanceIdJson.TryGetValue(out Guid? caller_AcsApplicationInstanceId) ? caller_AcsApplicationInstanceId : null, + Caller_AcsApplicationInstanceTenantId = jsonNodeDictionary[nameof(IKustoCallRecord.Caller_AcsApplicationInstanceTenantId)] is JsonValue caller_AcsApplicationInstanceTenantIdJson && caller_AcsApplicationInstanceTenantIdJson.TryGetValue(out Guid? caller_AcsApplicationInstanceTenantId) ? caller_AcsApplicationInstanceTenantId : null, + Caller_SpoolApplicationInstanceDisplayName = jsonNodeDictionary[nameof(IKustoCallRecord.Caller_SpoolApplicationInstanceDisplayName)] is JsonValue caller_SpoolApplicationInstanceDisplayNameJson && caller_SpoolApplicationInstanceDisplayNameJson.TryGetValue(out string? caller_SpoolApplicationInstanceDisplayName) ? caller_SpoolApplicationInstanceDisplayName : null, + Caller_SpoolApplicationInstanceId = jsonNodeDictionary[nameof(IKustoCallRecord.Caller_SpoolApplicationInstanceId)] is JsonValue caller_SpoolApplicationInstanceIdJson && caller_SpoolApplicationInstanceIdJson.TryGetValue(out Guid? caller_SpoolApplicationInstanceId) ? caller_SpoolApplicationInstanceId : null, + Caller_SpoolApplicationInstanceTenantId = jsonNodeDictionary[nameof(IKustoCallRecord.Caller_SpoolApplicationInstanceTenantId)] is JsonValue caller_SpoolApplicationInstanceTenantIdJson && caller_SpoolApplicationInstanceTenantIdJson.TryGetValue(out Guid? caller_SpoolApplicationInstanceTenantId) ? caller_SpoolApplicationInstanceTenantId : null, + Caller_EndpointType = jsonNodeDictionary[nameof(IKustoCallRecord.Caller_EndpointType)] is JsonValue caller_EndpointTypeJson && caller_EndpointTypeJson.TryGetValue(out string? caller_EndpointType) ? caller_EndpointType : null, + Caller_ProductFamily = jsonNodeDictionary[nameof(IKustoCallRecord.Caller_ProductFamily)] is JsonValue caller_ProductFamilyJson && caller_ProductFamilyJson.TryGetValue(out string? caller_ProductFamily) ? caller_ProductFamily : null, + Caller_Platform = jsonNodeDictionary[nameof(IKustoCallRecord.Caller_Platform)] is JsonValue caller_PlatformJson && caller_PlatformJson.TryGetValue(out string? caller_Platform) ? caller_Platform : null, + Caller_UserAgentHeaderValue = jsonNodeDictionary[nameof(IKustoCallRecord.Caller_UserAgentHeaderValue)] is JsonValue caller_UserAgentHeaderValueJson && caller_UserAgentHeaderValueJson.TryGetValue(out string? caller_UserAgentHeaderValue) ? caller_UserAgentHeaderValue : null, + Caller_ServiceRole = jsonNodeDictionary[nameof(IKustoCallRecord.Caller_ServiceRole)] is JsonValue caller_ServiceRoleJson && caller_ServiceRoleJson.TryGetValue(out string? caller_ServiceRole) ? caller_ServiceRole : null, + Caller_ApplicationVersion = jsonNodeDictionary[nameof(IKustoCallRecord.Caller_ApplicationVersion)] is JsonValue caller_ApplicationVersionJson && caller_ApplicationVersionJson.TryGetValue(out string? caller_ApplicationVersion) ? caller_ApplicationVersion : null, + Caller_AzureAdAppId = jsonNodeDictionary[nameof(IKustoCallRecord.Caller_AzureAdAppId)] is JsonValue caller_AzureAdAppIdJson && caller_AzureAdAppIdJson.TryGetValue(out Guid? caller_AzureAdAppId) ? caller_AzureAdAppId : null, + Caller_CommunicationServiceId = jsonNodeDictionary[nameof(IKustoCallRecord.Caller_CommunicationServiceId)] is JsonValue caller_CommunicationServiceIdJson && caller_CommunicationServiceIdJson.TryGetValue(out Guid? caller_CommunicationServiceId) ? caller_CommunicationServiceId : null, + Caller_ConnectionType = jsonNodeDictionary[nameof(IKustoCallRecord.Caller_ConnectionType)] is JsonValue caller_ConnectionTypeJson && caller_ConnectionTypeJson.TryGetValue(out string? caller_ConnectionType) ? caller_ConnectionType : null, + Caller_ReflexiveIPAddress = jsonNodeDictionary[nameof(IKustoCallRecord.Caller_ReflexiveIPAddress)] is JsonValue caller_ReflexiveIPAddressJson && caller_ReflexiveIPAddressJson.TryGetValue(out string? caller_ReflexiveIPAddress) ? caller_ReflexiveIPAddress : null, + Caller_Subnet = jsonNodeDictionary[nameof(IKustoCallRecord.Caller_Subnet)] is JsonValue caller_SubnetJson && caller_SubnetJson.TryGetValue(out string? caller_Subnet) ? caller_Subnet : null, + Caller_IpAddress = jsonNodeDictionary[nameof(IKustoCallRecord.Caller_IpAddress)] is JsonValue caller_IpAddressJson && caller_IpAddressJson.TryGetValue(out string? caller_IpAddress) ? caller_IpAddress : null, + Caller_MacAddress = jsonNodeDictionary[nameof(IKustoCallRecord.Caller_MacAddress)] is JsonValue caller_MacAddressJson && caller_MacAddressJson.TryGetValue(out string? caller_MacAddress) ? caller_MacAddress : null, + Caller_LinkSpeed = jsonNodeDictionary[nameof(IKustoCallRecord.Caller_LinkSpeed)] is JsonValue caller_LinkSpeedJson && caller_LinkSpeedJson.TryGetValue(out long? caller_LinkSpeed) ? caller_LinkSpeed : null, + Caller_NetworkTransportProtocol = jsonNodeDictionary[nameof(IKustoCallRecord.Caller_NetworkTransportProtocol)] is JsonValue caller_NetworkTransportProtocolJson && caller_NetworkTransportProtocolJson.TryGetValue(out string? caller_NetworkTransportProtocol) ? caller_NetworkTransportProtocol : null, + Caller_Port = jsonNodeDictionary[nameof(IKustoCallRecord.Caller_Port)] is JsonValue caller_PortJson && caller_PortJson.TryGetValue(out int? caller_Port) ? caller_Port : null, + Caller_RelayIPAddress = jsonNodeDictionary[nameof(IKustoCallRecord.Caller_RelayIPAddress)] is JsonValue caller_RelayIPAddressJson && caller_RelayIPAddressJson.TryGetValue(out string? caller_RelayIPAddress) ? caller_RelayIPAddress : null, + Caller_RelayPort = jsonNodeDictionary[nameof(IKustoCallRecord.Caller_RelayPort)] is JsonValue caller_RelayPortJson && caller_RelayPortJson.TryGetValue(out int? caller_RelayPort) ? caller_RelayPort : null, + Caller_DnsSuffix = jsonNodeDictionary[nameof(IKustoCallRecord.Caller_DnsSuffix)] is JsonValue caller_DnsSuffixJson && caller_DnsSuffixJson.TryGetValue(out string? caller_DnsSuffix) ? caller_DnsSuffix : null, + Caller_TraceRouteHops = jsonNodeDictionary[nameof(IKustoCallRecord.Caller_TraceRouteHops)] is JsonValue caller_TraceRouteHopsJson && caller_TraceRouteHopsJson.TryGetValue(out string? caller_TraceRouteHops) ? caller_TraceRouteHops : null, + Caller_BSSID = jsonNodeDictionary[nameof(IKustoCallRecord.Caller_BSSID)] is JsonValue caller_BSSIDJson && caller_BSSIDJson.TryGetValue(out string? caller_BSSID) ? caller_BSSID : null, + Caller_WifiRadioType = jsonNodeDictionary[nameof(IKustoCallRecord.Caller_WifiRadioType)] is JsonValue caller_WifiRadioTypeJson && caller_WifiRadioTypeJson.TryGetValue(out string? caller_WifiRadioType) ? caller_WifiRadioType : null, + Caller_WifiBand = jsonNodeDictionary[nameof(IKustoCallRecord.Caller_WifiBand)] is JsonValue caller_WifiBandJson && caller_WifiBandJson.TryGetValue(out string? caller_WifiBand) ? caller_WifiBand : null, + Caller_WifiChannel = jsonNodeDictionary[nameof(IKustoCallRecord.Caller_WifiChannel)] is JsonValue caller_WifiChannelJson && caller_WifiChannelJson.TryGetValue(out int? caller_WifiChannel) ? caller_WifiChannel : null, + Caller_WifiSignalStrength = jsonNodeDictionary[nameof(IKustoCallRecord.Caller_WifiSignalStrength)] is JsonValue caller_WifiSignalStrengthJson && caller_WifiSignalStrengthJson.TryGetValue(out int? caller_WifiSignalStrength) ? caller_WifiSignalStrength : null, + Caller_WifiBatteryCharge = jsonNodeDictionary[nameof(IKustoCallRecord.Caller_WifiBatteryCharge)] is JsonValue caller_WifiBatteryChargeJson && caller_WifiBatteryChargeJson.TryGetValue(out int? caller_WifiBatteryCharge) ? caller_WifiBatteryCharge : null, + Caller_WifiMicrosoftDriver = jsonNodeDictionary[nameof(IKustoCallRecord.Caller_WifiMicrosoftDriver)] is JsonValue caller_WifiMicrosoftDriverJson && caller_WifiMicrosoftDriverJson.TryGetValue(out string? caller_WifiMicrosoftDriver) ? caller_WifiMicrosoftDriver : null, + Caller_WifiMicrosoftDriverVersion = jsonNodeDictionary[nameof(IKustoCallRecord.Caller_WifiMicrosoftDriverVersion)] is JsonValue caller_WifiMicrosoftDriverVersionJson && caller_WifiMicrosoftDriverVersionJson.TryGetValue(out string? caller_WifiMicrosoftDriverVersion) ? caller_WifiMicrosoftDriverVersion : null, + Caller_WifiVendorDriver = jsonNodeDictionary[nameof(IKustoCallRecord.Caller_WifiVendorDriver)] is JsonValue caller_WifiVendorDriverJson && caller_WifiVendorDriverJson.TryGetValue(out string? caller_WifiVendorDriver) ? caller_WifiVendorDriver : null, + Caller_WifiVendorDriverVersion = jsonNodeDictionary[nameof(IKustoCallRecord.Caller_WifiVendorDriverVersion)] is JsonValue caller_WifiVendorDriverVersionJson && caller_WifiVendorDriverVersionJson.TryGetValue(out string? caller_WifiVendorDriverVersion) ? caller_WifiVendorDriverVersion : null, + Caller_CaptureDeviceName = jsonNodeDictionary[nameof(IKustoCallRecord.Caller_CaptureDeviceName)] is JsonValue caller_CaptureDeviceNameJson && caller_CaptureDeviceNameJson.TryGetValue(out string? caller_CaptureDeviceName) ? caller_CaptureDeviceName : null, + Caller_CaptureDeviceDriver = jsonNodeDictionary[nameof(IKustoCallRecord.Caller_CaptureDeviceDriver)] is JsonValue caller_CaptureDeviceDriverJson && caller_CaptureDeviceDriverJson.TryGetValue(out string? caller_CaptureDeviceDriver) ? caller_CaptureDeviceDriver : null, + Caller_RenderDeviceName = jsonNodeDictionary[nameof(IKustoCallRecord.Caller_RenderDeviceName)] is JsonValue caller_RenderDeviceNameJson && caller_RenderDeviceNameJson.TryGetValue(out string? caller_RenderDeviceName) ? caller_RenderDeviceName : null, + Caller_RenderDeviceDriver = jsonNodeDictionary[nameof(IKustoCallRecord.Caller_RenderDeviceDriver)] is JsonValue caller_RenderDeviceDriverJson && caller_RenderDeviceDriverJson.TryGetValue(out string? caller_RenderDeviceDriver) ? caller_RenderDeviceDriver : null, + Caller_SentSignalLevel = jsonNodeDictionary[nameof(IKustoCallRecord.Caller_SentSignalLevel)] is JsonValue caller_SentSignalLevelJson && caller_SentSignalLevelJson.TryGetValue(out long? caller_SentSignalLevel) ? caller_SentSignalLevel : null, + Caller_SentNoiseLevel = jsonNodeDictionary[nameof(IKustoCallRecord.Caller_SentNoiseLevel)] is JsonValue caller_SentNoiseLevelJson && caller_SentNoiseLevelJson.TryGetValue(out long? caller_SentNoiseLevel) ? caller_SentNoiseLevel : null, + Caller_MicGlitchRate = jsonNodeDictionary[nameof(IKustoCallRecord.Caller_MicGlitchRate)] is JsonValue caller_MicGlitchRateJson && caller_MicGlitchRateJson.TryGetValue(out long? caller_MicGlitchRate) ? caller_MicGlitchRate : null, + Caller_ReceivedSignalLevel = jsonNodeDictionary[nameof(IKustoCallRecord.Caller_ReceivedSignalLevel)] is JsonValue caller_ReceivedSignalLevelJson && caller_ReceivedSignalLevelJson.TryGetValue(out long? caller_ReceivedSignalLevel) ? caller_ReceivedSignalLevel : null, + Caller_ReceivedNoiseLevel = jsonNodeDictionary[nameof(IKustoCallRecord.Caller_ReceivedNoiseLevel)] is JsonValue caller_ReceivedNoiseLevelJson && caller_ReceivedNoiseLevelJson.TryGetValue(out long? caller_ReceivedNoiseLevel) ? caller_ReceivedNoiseLevel : null, + Caller_SpeakerGlitchRate = jsonNodeDictionary[nameof(IKustoCallRecord.Caller_SpeakerGlitchRate)] is JsonValue caller_SpeakerGlitchRateJson && caller_SpeakerGlitchRateJson.TryGetValue(out long? caller_SpeakerGlitchRate) ? caller_SpeakerGlitchRate : null, + Caller_HowlingEventCount = jsonNodeDictionary[nameof(IKustoCallRecord.Caller_HowlingEventCount)] is JsonValue caller_HowlingEventCountJson && caller_HowlingEventCountJson.TryGetValue(out int? caller_HowlingEventCount) ? caller_HowlingEventCount : null, + Caller_InitialSignalLevelRootMeanSquare = jsonNodeDictionary[nameof(IKustoCallRecord.Caller_InitialSignalLevelRootMeanSquare)] is JsonValue caller_InitialSignalLevelRootMeanSquareJson && caller_InitialSignalLevelRootMeanSquareJson.TryGetValue(out long? caller_InitialSignalLevelRootMeanSquare) ? caller_InitialSignalLevelRootMeanSquare : null, + Caller_DeviceGlitchEventRatio = jsonNodeDictionary[nameof(IKustoCallRecord.Caller_DeviceGlitchEventRatio)] is JsonValue caller_DeviceGlitchEventRatioJson && caller_DeviceGlitchEventRatioJson.TryGetValue(out double? caller_DeviceGlitchEventRatio) ? caller_DeviceGlitchEventRatio : null, + Caller_DeviceClippingEventRatio = jsonNodeDictionary[nameof(IKustoCallRecord.Caller_DeviceClippingEventRatio)] is JsonValue caller_DeviceClippingEventRatioJson && caller_DeviceClippingEventRatioJson.TryGetValue(out double? caller_DeviceClippingEventRatio) ? caller_DeviceClippingEventRatio : null, + Caller_LowSpeechToNoiseEventRatio = jsonNodeDictionary[nameof(IKustoCallRecord.Caller_LowSpeechToNoiseEventRatio)] is JsonValue caller_LowSpeechToNoiseEventRatioJson && caller_LowSpeechToNoiseEventRatioJson.TryGetValue(out double? caller_LowSpeechToNoiseEventRatio) ? caller_LowSpeechToNoiseEventRatio : null, + Caller_CaptureNotFunctioningEventRatio = jsonNodeDictionary[nameof(IKustoCallRecord.Caller_CaptureNotFunctioningEventRatio)] is JsonValue caller_CaptureNotFunctioningEventRatioJson && caller_CaptureNotFunctioningEventRatioJson.TryGetValue(out double? caller_CaptureNotFunctioningEventRatio) ? caller_CaptureNotFunctioningEventRatio : null, + Caller_SentQualityEventRatio = jsonNodeDictionary[nameof(IKustoCallRecord.Caller_SentQualityEventRatio)] is JsonValue caller_SentQualityEventRatioJson && caller_SentQualityEventRatioJson.TryGetValue(out double? caller_SentQualityEventRatio) ? caller_SentQualityEventRatio : null, + Caller_LowSpeechLevelEventRatio = jsonNodeDictionary[nameof(IKustoCallRecord.Caller_LowSpeechLevelEventRatio)] is JsonValue caller_LowSpeechLevelEventRatioJson && caller_LowSpeechLevelEventRatioJson.TryGetValue(out double? caller_LowSpeechLevelEventRatio) ? caller_LowSpeechLevelEventRatio : null, + Caller_RenderNotFunctioningEventRatio = jsonNodeDictionary[nameof(IKustoCallRecord.Caller_RenderNotFunctioningEventRatio)] is JsonValue caller_RenderNotFunctioningEventRatioJson && caller_RenderNotFunctioningEventRatioJson.TryGetValue(out double? caller_RenderNotFunctioningEventRatio) ? caller_RenderNotFunctioningEventRatio : null, + Caller_ReceivedQualityEventRatio = jsonNodeDictionary[nameof(IKustoCallRecord.Caller_ReceivedQualityEventRatio)] is JsonValue caller_ReceivedQualityEventRatioJson && caller_ReceivedQualityEventRatioJson.TryGetValue(out double? caller_ReceivedQualityEventRatio) ? caller_ReceivedQualityEventRatio : null, + Caller_RenderZeroVolumeEventRatio = jsonNodeDictionary[nameof(IKustoCallRecord.Caller_RenderZeroVolumeEventRatio)] is JsonValue caller_RenderZeroVolumeEventRatioJson && caller_RenderZeroVolumeEventRatioJson.TryGetValue(out double? caller_RenderZeroVolumeEventRatio) ? caller_RenderZeroVolumeEventRatio : null, + Caller_RenderMuteEventRatio = jsonNodeDictionary[nameof(IKustoCallRecord.Caller_RenderMuteEventRatio)] is JsonValue caller_RenderMuteEventRatioJson && caller_RenderMuteEventRatioJson.TryGetValue(out double? caller_RenderMuteEventRatio) ? caller_RenderMuteEventRatio : null, + Caller_CpuInsufficentEventRatio = jsonNodeDictionary[nameof(IKustoCallRecord.Caller_CpuInsufficentEventRatio)] is JsonValue caller_CpuInsufficentEventRatioJson && caller_CpuInsufficentEventRatioJson.TryGetValue(out double? caller_CpuInsufficentEventRatio) ? caller_CpuInsufficentEventRatio : null, + Caller_DelayEventRatio = jsonNodeDictionary[nameof(IKustoCallRecord.Caller_DelayEventRatio)] is JsonValue caller_DelayEventRatioJson && caller_DelayEventRatioJson.TryGetValue(out double? caller_DelayEventRatio) ? caller_DelayEventRatio : null, + Caller_BandwidthLowEventRatio = jsonNodeDictionary[nameof(IKustoCallRecord.Caller_BandwidthLowEventRatio)] is JsonValue caller_BandwidthLowEventRatioJson && caller_BandwidthLowEventRatioJson.TryGetValue(out double? caller_BandwidthLowEventRatio) ? caller_BandwidthLowEventRatio : null, + Caller_FeedbackRating = jsonNodeDictionary[nameof(IKustoCallRecord.Caller_FeedbackRating)] is JsonValue caller_FeedbackRatingJson && caller_FeedbackRatingJson.TryGetValue(out string? caller_FeedbackRating) ? caller_FeedbackRating : null, + Caller_FeedbackText = jsonNodeDictionary[nameof(IKustoCallRecord.Caller_FeedbackText)] is JsonValue caller_FeedbackTextJson && caller_FeedbackTextJson.TryGetValue(out string? caller_FeedbackText) ? caller_FeedbackText : null, + Caller_FeedbackTokens = jsonNodeDictionary[nameof(IKustoCallRecord.Caller_FeedbackTokens)] is JsonValue caller_FeedbackTokensJson && caller_FeedbackTokensJson.TryGetValue(out string? caller_FeedbackTokens) ? caller_FeedbackTokens : null + }; + } + } +} \ No newline at end of file diff --git a/src/Flattener/Extensions/IParsableExtensions.cs b/src/Flattener/Extensions/IParsableExtensions.cs new file mode 100644 index 0000000..afdb584 --- /dev/null +++ b/src/Flattener/Extensions/IParsableExtensions.cs @@ -0,0 +1,164 @@ +using Microsoft.Kiota.Abstractions; +using Microsoft.Kiota.Abstractions.Serialization; +using Microsoft.Kiota.Serialization.Json; +using System.Collections.Generic; +using System.IO; +using System.Text; +using System.Threading.Tasks; + +namespace CallRecordInsights.Extensions +{ + public static class IParsableExtensions + { + private const string ContentType = "application/json"; + + static IParsableExtensions() + { + ApiClientBuilder.RegisterDefaultDeserializer(); + } + + /// + /// Serializes a given object to a JSON string in a synchronous manner. + /// + /// + /// + /// + public static string SerializeAsString(this T item) where T : IParsable + { + using var streamReader = new StreamReader(item.SerializeAsUTF8Stream(), Encoding.UTF8); + return streamReader.ReadToEnd(); + } + + /// + /// Serializes a given object to a JSON string. + /// + /// + /// + /// + public static async Task SerializeAsStringAsync(this T item) where T : IParsable + { + using var streamReader = new StreamReader(item.SerializeAsUTF8Stream(), Encoding.UTF8); + return await streamReader.ReadToEndAsync(); + } + + /// + /// Serializes a given collection to a JSON string in a synchronous manner. + /// + /// + /// + /// + public static string SerializeAsString(this IEnumerable items) where T : IParsable + { + using var streamReader = new StreamReader(items.SerializeAsUTF8Stream(), Encoding.UTF8); + return streamReader.ReadToEnd(); + } + + /// + /// Serializes a given collection to a JSON string. + /// + /// + /// + /// + public static async Task SerializeAsStringAsync(this IEnumerable items) where T : IParsable + { + using var streamReader = new StreamReader(items.SerializeAsUTF8Stream(), Encoding.UTF8); + return await streamReader.ReadToEndAsync(); + } + + /// + /// Serializes a given dictionary to a JSON string in a synchronous manner. + /// + /// + /// + /// + public static string SerializeAsString(this IDictionary dictionary) where T : IParsable + { + using var streamReader = new StreamReader(dictionary.SerializeAsUTF8Stream(), Encoding.UTF8); + return streamReader.ReadToEnd(); + } + + /// + /// Serializes a given dictionary to a JSON string. + /// + /// + /// + /// + public static async Task SerializeAsStringAsync(this IDictionary dictionary) where T : IParsable + { + using var streamReader = new StreamReader(dictionary.SerializeAsUTF8Stream(), Encoding.UTF8); + return await streamReader.ReadToEndAsync(); + } + + /// + /// Deserializes a given JSON string to a object in a synchronous manner. + /// + /// + /// + /// + public static T? DeserializeObject(this string json) where T : IParsable, new() + { + var parsableFactory = ParseNodeFactoryRegistry.DefaultInstance; + using var stream = new MemoryStream(Encoding.UTF8.GetBytes(json)); + var rootNode = parsableFactory.GetRootParseNode(ContentType, stream); + return rootNode.GetObjectValue((IParseNode item) => new T()); + } + + /// + /// Deserializes a given JSON string to a object. + /// + /// + /// + /// + public static IEnumerable DeserializeCollection(this string json) where T : IParsable, new() + { + var parsableFactory = ParseNodeFactoryRegistry.DefaultInstance; + using var stream = new MemoryStream(Encoding.UTF8.GetBytes(json)); + var rootNode = parsableFactory.GetRootParseNode(ContentType, stream); + return rootNode.GetCollectionOfObjectValues((IParseNode item) => new T()); + } + + /// + /// Serializes a given object to a JSON UTF-8 stream in a synchronous manner. + /// + /// + /// + /// + public static Stream SerializeAsUTF8Stream(this T item) where T : IParsable + { + using var writer = new JsonSerializationWriter(); + writer.WriteObjectValue(null, item); + return writer.GetSerializedContent(); + } + + /// + /// Serializes a given collection to a JSON UTF-8 stream in a synchronous manner. + /// + /// + /// + /// + public static Stream SerializeAsUTF8Stream(this IEnumerable items) where T : IParsable + { + using var writer = new JsonSerializationWriter(); + writer.WriteCollectionOfObjectValues(null, items); + return writer.GetSerializedContent(); + } + + /// + /// Serializes a given dictionary to a JSON UTF-8 stream in a synchronous manner. + /// + /// + /// + /// + public static Stream SerializeAsUTF8Stream(this IDictionary dictionary) where T : IParsable + { + using var writer = new JsonSerializationWriter(); + writer.writer.WriteStartObject(); + foreach (var kvp in dictionary) + { + writer.WriteObjectValue(kvp.Key, kvp.Value); + } + writer.writer.WriteEndObject(); + return writer.GetSerializedContent(); + } + } +} \ No newline at end of file diff --git a/src/Flattener/Extensions/JsonPathExtensions.cs b/src/Flattener/Extensions/JsonPathExtensions.cs new file mode 100644 index 0000000..45ef704 --- /dev/null +++ b/src/Flattener/Extensions/JsonPathExtensions.cs @@ -0,0 +1,593 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.Json.Nodes; +using System.Text.RegularExpressions; + +namespace CallRecordInsights.Extensions +{ + public static class JsonPathExtensions + { + /// + /// Selects a single token from the provided node using the provided JSON path. + /// + /// + /// + /// + public static JsonNode? SelectToken(this JsonNode node, ReadOnlySpan jsonPath) + { + var tokens = node.SelectTokens(jsonPath); + return tokens.FirstOrDefault(); + } + + /// + /// Selects all tokens from the provided node using the provided JSON path. + /// + /// + /// + /// + /// + public static IEnumerable SelectTokens(this JsonNode node, ReadOnlySpan jsonPath) + { + var selectors = ParseSelectors(jsonPath).ToList(); + var tokens = new List() { node }; + + foreach (var selector in selectors) + { + tokens = selector switch + { + ObjectPropertySelector propertySelector => SelectTokensForPropertySelector(tokens, propertySelector).ToList(), + ArrayWildcardSelector wildcardSelector => SelectTokensForArrayWildcardSelector(tokens, wildcardSelector).ToList(), + ArrayIndexSelector indexSelector => SelectTokensForArrayIndexSelector(tokens, indexSelector).ToList(), + ArraySliceSelector sliceSelector => SelectTokensForArraySliceSelector(tokens, sliceSelector).ToList(), + _ => throw new InvalidOperationException($"Invalid selector type: {selector.GetType()}"), + }; + } + + return tokens; + } + + private static readonly Regex JsonPathSeparator = new("(? + /// Gets the ranges of the selectors in the provided JSON path. + /// + /// + /// + private static IReadOnlyList GetSelectorRanges(ReadOnlySpan jsonPath) + { + var selectors = new List(); + if (!jsonPath.Contains('.')) + { + selectors.Add(new(0, jsonPath.Length)); + return selectors; + } + var index = 0; + if (jsonPath.Contains('\'') || jsonPath.Contains('"')) + { + var parts = JsonPathSeparator.Split(jsonPath.ToString()); + foreach (var part in parts) + { + if (part.Length == 0) + continue; + selectors.Add(new(index, index + part.Length)); + index += part.Length + 1; + } + return selectors; + } + while (index < jsonPath.Length) + { + var start = index; + while (index < jsonPath.Length && jsonPath[index] != '.') + { + index++; + } + if (index - start > 0) + selectors.Add(new(start, index)); + index++; + } + return selectors; + } + + /// + /// Parses the provided JSON path into a list of selectors. + /// + /// + /// + /// + private static IEnumerable ParseSelectors(ReadOnlySpan jsonPath) + { + var selectors = new List(); + foreach (var range in GetSelectorRanges(jsonPath)) + { + var selector = jsonPath[range]; + if (selector == null || selector.Length == 0 || (selector.Length == 1 && selector[0] == '$')) + continue; + + if (selector[^1] == ']') + { + var openBracketIndex = selector.LastIndexOf('['); + if (openBracketIndex == -1) + throw new InvalidOperationException($"Invalid selector: {selector}"); + + var prefix = selector[..openBracketIndex]; + var indexOrWildcard = selector.Slice(openBracketIndex + 1, selector.Length - openBracketIndex - 2); + if (prefix.Length > 0) + selectors.Add(new ObjectPropertySelector(prefix)); + if (indexOrWildcard.Length == 0 || (indexOrWildcard.Length == 1 && indexOrWildcard[0] == '*')) + selectors.Add(new ArrayWildcardSelector()); + else if (indexOrWildcard.IndexOf(':') != -1) + selectors.Add(ArraySliceSelector.Parse(indexOrWildcard)); + else if (int.TryParse(indexOrWildcard, out var index)) + selectors.Add(new ArrayIndexSelector(index)); + else + selectors.Add(new ObjectPropertySelector(indexOrWildcard.Trim("'\""))); + + continue; + } + + selectors.Add(new ObjectPropertySelector(selector)); + } + return selectors; + } + + /// + /// Selects all tokens from all provided nodes using the provided JSON path. + /// + /// + /// + /// + private static IEnumerable SelectTokensForPropertySelector(IEnumerable tokens, ObjectPropertySelector selector) + { + return tokens.SelectMany(token => + { + if (token is JsonObject jsonObject && jsonObject.TryGetPropertyValue(selector.PropertyName, out var propertyValue)) + { + if (propertyValue is JsonArray array) + { + return array; + } + + return new[] { propertyValue }; + } + + return Enumerable.Empty(); + }); + } + + /// + /// Selects all tokens from all provided nodes using the provided JSON path. + /// + /// + /// + /// + private static IEnumerable SelectTokensForArrayWildcardSelector(IEnumerable tokens, ArrayWildcardSelector wildcardSelector) + { + return tokens; + } + + /// + /// Selects all tokens from all provided nodes using the provided JSON path. + /// + /// + /// + /// + private static IEnumerable SelectTokensForArrayIndexSelector(IEnumerable tokens, ArrayIndexSelector selector) + { + var index = selector.Index; + if ((index.Value > 0 || index.Value == 0 && !index.IsFromEnd) && index.Value < tokens.Count()) + return new[] { tokens.ElementAt(index.Value) }; + + return Enumerable.Empty(); + } + + /// + /// Selects all tokens from all provided nodes using the provided JSON path. + /// + /// + /// + /// + private static IEnumerable SelectTokensForArraySliceSelector(IEnumerable tokens, ArraySliceSelector selector) + { + var selected = tokens.Take(selector.Range).ToList(); + if (selector.Step == 1) + return selected; + + var selectedItems = new List(); + for (var i = 0; i < selected.Count; i += selector.Step) + { + selectedItems.Add(selected[i]); + } + return selectedItems; + } + + /// + /// Parses the provided JSON path into a list of selectors. + /// + /// + /// + public static IEnumerable ParseJsonPath(this string jsonPath) => ParseJsonPath(jsonPath.AsSpan()); + public static IEnumerable ParseJsonPath(this ReadOnlySpan jsonPath) => ParseSelectors(jsonPath); + + /// + /// Determines whether the provided JSON path is a parent of the provided child JSON path. + /// + /// + /// + /// + /// + public static bool IsParentOf(this string parentPath, string childPath, StringComparison comparisonType = StringComparison.Ordinal) => IsParentOf(parentPath.AsSpan(), childPath.AsSpan(), comparisonType); + public static bool IsParentOf(this ReadOnlySpan parentPath, ReadOnlySpan childPath, StringComparison comparisonType = StringComparison.Ordinal) => IsParentOf(ParseJsonPath(parentPath), ParseJsonPath(childPath), comparisonType); + public static bool IsParentOf(this IEnumerable parentPath, IEnumerable childPath, StringComparison comparisonType = StringComparison.Ordinal) + { + var parentSelectors = parentPath.ToList(); + var childSelectors = childPath.ToList(); + + if (parentSelectors.Count >= childSelectors.Count) + return false; + + for (var i = 0; i < parentSelectors.Count; i++) + { + // if they are not of the same type, they are not the same + if (parentSelectors[i] is IArraySelector && childSelectors[i] is not IArraySelector) + return false; + + if (parentSelectors[i] is not IArraySelector && childSelectors[i] is IArraySelector) + return false; + + if (parentSelectors[i] is ObjectPropertySelector parentPropertySelector && childSelectors[i] is ObjectPropertySelector childPropertySelector + && !parentPropertySelector.Equals(childPropertySelector, comparisonType)) + return false; + } + + return true; + } + + /// + /// Determines whether the provided JSON paths are at the same level in the JSON structure. + /// + /// + /// + /// + /// + public static bool IsSiblingOf(this string sourcePath, string targetPath, StringComparison comparisonType = StringComparison.Ordinal) => IsSiblingOf(sourcePath.AsSpan(), targetPath.AsSpan(), comparisonType); + public static bool IsSiblingOf(this ReadOnlySpan sourcePath, ReadOnlySpan targetPath, StringComparison comparisonType = StringComparison.Ordinal) => IsSiblingOf(ParseJsonPath(sourcePath), ParseJsonPath(targetPath), comparisonType); + public static bool IsSiblingOf(this IEnumerable sourcePath, IEnumerable targetPath, StringComparison comparisonType = StringComparison.Ordinal) + { + var sourceSelectors = sourcePath.ToList(); + var targetSelectors = targetPath.ToList(); + + if (sourceSelectors.Count != targetSelectors.Count) + return false; + + for (var i = 0; i < sourceSelectors.Count; i++) + { + // if they are not of the same type, they are not the same + if (sourceSelectors[i] is IArraySelector && targetSelectors[i] is not IArraySelector) + return false; + + if (sourceSelectors[i] is not IArraySelector && targetSelectors[i] is IArraySelector) + return false; + + if (sourceSelectors[i] is ObjectPropertySelector sourcePropertySelector && targetSelectors[i] is ObjectPropertySelector targetPropertySelector + && !sourcePropertySelector.Equals(targetPropertySelector, comparisonType)) + return false; + } + + if (MemoryExtensions.Equals(sourcePath.GetParentPath(), targetPath.GetParentPath(), comparisonType)) + { + if (sourceSelectors[^1] is ObjectPropertySelector sourcePropertySelector && targetSelectors[^1] is ObjectPropertySelector targetPropertySelector) + return !sourcePropertySelector.Equals(targetPropertySelector, comparisonType); + + return true; + } + + return false; + } + + /// + /// Determines whether the provided JSON paths are on the same unique parent path in the JSON structure. + /// + /// + /// + /// + /// + public static bool IsRelativeOf(this string sourcePath, string targetPath, StringComparison comparisonType = StringComparison.Ordinal) => IsRelativeOf(sourcePath.AsSpan(), targetPath.AsSpan(), comparisonType); + public static bool IsRelativeOf(this ReadOnlySpan sourcePath, ReadOnlySpan targetPath, StringComparison comparisonType = StringComparison.Ordinal) => IsRelativeOf(ParseJsonPath(sourcePath), ParseJsonPath(targetPath), comparisonType); + public static bool IsRelativeOf(this IEnumerable potentialRelative, IEnumerable otherPotentialRelative, StringComparison comparisonType = StringComparison.Ordinal) + { + var potentialExpansion = GetClosestExpansionAsEnumerable(potentialRelative); + var otherPotentialExpansion = GetClosestExpansionAsEnumerable(otherPotentialRelative); + foreach ((var potential, var other) in potentialExpansion.Zip(otherPotentialExpansion)) + { + if (potential is IArraySelector && other is not IArraySelector) + return false; + + if (potential is not IArraySelector && other is IArraySelector) + return false; + + if (potential is ObjectPropertySelector potentialPropertySelector + && other is ObjectPropertySelector otherPotentialPropertySelector + && !potentialPropertySelector.Equals(otherPotentialPropertySelector, comparisonType)) + return false; + + if (potential.ToString() != other.ToString()) + return false; + } + return true; + } + + /// + /// Gets the closest expandable ancestor of the provided JSON path. + /// + /// + /// + public static ReadOnlySpan GetClosestExpansion(this string path) => GetClosestExpansion(path.AsSpan()); + public static ReadOnlySpan GetClosestExpansion(this ReadOnlySpan path) => GetClosestExpansion(ParseJsonPath(path)); + public static ReadOnlySpan GetClosestExpansion(this IEnumerable path) => ToJsonPath(GetClosestExpansionAsEnumerable(path)); + public static IEnumerable GetClosestExpansionAsEnumerable(this IEnumerable path) + { + var pathArray = path.ToList(); + var i = pathArray.Count - 1; + while (i >= 0 && pathArray[i] is not IArraySelector) + { + i--; + } + return path.Take(i + 1); + } + + /// + /// Gets the number of levels of expansion in the provided JSON path. + /// + /// + /// + public static int LevelsOfExpansion(this string path) => LevelsOfExpansion(path.AsSpan()); + public static int LevelsOfExpansion(this ReadOnlySpan path) => LevelsOfExpansion(ParseJsonPath(path)); + public static int LevelsOfExpansion(this IEnumerable path) => path.Count(s => s is IArraySelector); + + /// + /// Finds the closest common ancestor of the provided JSON paths. + /// + /// + /// + /// + /// + public static ReadOnlySpan GetCommonAncestor(this string sourcePath, string targetPath, StringComparison comparisonType = StringComparison.Ordinal) => GetCommonAncestor(sourcePath.AsSpan(), targetPath.AsSpan(), comparisonType); + public static ReadOnlySpan GetCommonAncestor(this string sourcePath, IEnumerable targetPath, StringComparison comparisonType = StringComparison.Ordinal) => GetCommonAncestor(sourcePath.AsSpan(), targetPath, comparisonType); + public static ReadOnlySpan GetCommonAncestor(this IEnumerable sourcePath, string targetPath, StringComparison comparisonType = StringComparison.Ordinal) => GetCommonAncestor(sourcePath, targetPath.AsSpan(), comparisonType); + public static ReadOnlySpan GetCommonAncestor(this ReadOnlySpan sourcePath, ReadOnlySpan targetPath, StringComparison comparisonType = StringComparison.Ordinal) => GetCommonAncestor(ParseJsonPath(sourcePath), ParseJsonPath(targetPath), comparisonType); + public static ReadOnlySpan GetCommonAncestor(this ReadOnlySpan sourcePath, IEnumerable targetPath, StringComparison comparisonType = StringComparison.Ordinal) => GetCommonAncestor(ParseJsonPath(sourcePath), targetPath, comparisonType); + public static ReadOnlySpan GetCommonAncestor(this IEnumerable sourcePath, ReadOnlySpan targetPath, StringComparison comparisonType = StringComparison.Ordinal) => GetCommonAncestor(sourcePath, ParseJsonPath(targetPath), comparisonType); + public static ReadOnlySpan GetCommonAncestor(this IEnumerable sourcePath, IEnumerable targetPath, StringComparison comparisonType = StringComparison.Ordinal) => ToJsonPath(GetCommonAncestorAsEnumerable(sourcePath, targetPath, comparisonType)); + public static IEnumerable GetCommonAncestorAsEnumerable(this IEnumerable sourcePath, IEnumerable targetPath, StringComparison comparisonType = StringComparison.Ordinal) + { + var sourceSelectors = sourcePath.ToList(); + var targetSelectors = targetPath.ToList(); + + var searchEnd = Math.Min(sourceSelectors.Count, targetSelectors.Count); + + var commonAncestor = new List(); + for (var i = 0; i < searchEnd; i++) + { + // if they are not of the same type, they are not the same + if (sourceSelectors[i] is IArraySelector && targetSelectors[i] is not IArraySelector) + break; + + if (sourceSelectors[i] is not IArraySelector && targetSelectors[i] is IArraySelector) + break; + + if (sourceSelectors[i] is ObjectPropertySelector sourcePropertySelector + && targetSelectors[i] is ObjectPropertySelector targetPropertySelector + && !sourcePropertySelector.Equals(targetPropertySelector, comparisonType)) + break; + + commonAncestor.Add(sourceSelectors[i]); + } + return commonAncestor; + } + + /// + /// Determines whether the provided JSON path is expandable. + /// + /// + /// + public static bool IsExpandable(this string path) => IsExpandable(path.AsSpan()); + public static bool IsExpandable(this ReadOnlySpan path) => IsExpandable(ParseJsonPath(path)); + public static bool IsExpandable(this IEnumerable path) => path.Any(s => s is IArraySelector && s is not ArrayIndexSelector); + + /// + /// Converts the provided JSON path to a string. + /// + /// + /// + public static ReadOnlySpan ToJsonPath(this string path) => ToJsonPath(path.AsSpan()); + public static ReadOnlySpan ToJsonPath(this ReadOnlySpan path) => ToJsonPath(ParseJsonPath(path)); + public static ReadOnlySpan ToJsonPath(this IEnumerable path) + { + var builder = new StringBuilder("$"); + foreach (var selector in path) + { + selector.AppendTo(builder); + } + return builder.ToString(); + } + + /// + /// Gets the parent path of the provided JSON path. + /// + /// + /// + public static ReadOnlySpan GetParentPath(this string path) => GetParentPath(path.AsSpan()); + public static ReadOnlySpan GetParentPath(this ReadOnlySpan path) => GetParentPath(ParseJsonPath(path)); + public static ReadOnlySpan GetParentPath(this IEnumerable path) => ToJsonPath(GetParentPathAsEnumerable(path)); + public static IEnumerable GetParentPathAsEnumerable(this IEnumerable path) + { + return path.SkipLast(1); + } + } + + public interface ISelector + { + StringBuilder AppendTo(StringBuilder builder); + } + + public interface IArraySelector : ISelector + { + } + + public class ArrayWildcardSelector : IArraySelector + { + public StringBuilder AppendTo(StringBuilder builder) + { + return builder.Append("[*]"); + } + + public override string ToString() + { + return "[*]"; + } + } + + public class ArrayIndexSelector : IArraySelector + { + public Index Index { get; } + private readonly int _index; + + public ArrayIndexSelector(int index) + { + _index = index; + Index = index >= 0 ? Index.FromStart(index) : Index.FromEnd(-index); + } + + public StringBuilder AppendTo(StringBuilder builder) + { + builder.Append('['); + builder.Append(_index); + builder.Append(']'); + return builder; + } + + public override string ToString() + { + return AppendTo(new StringBuilder()).ToString(); + } + } + + public class ArraySliceSelector : IArraySelector + { + public Index Start { get; } + private readonly int? _start; + + public Index End { get; } + private readonly int? _end; + public int Step { get; } + + public Range Range => new(Start, End); + + public ArraySliceSelector(int? start, int? end, int step) + { + Start = start != null ? start >= 0 ? Index.FromStart(start.Value) : Index.FromEnd(-start.Value) : Index.Start; + _start = start; + End = end != null ? end >= 0 ? Index.FromStart(end.Value) : Index.FromEnd(-end.Value) : Index.End; + _end = end; + if (step <= 0) + throw new InvalidOperationException("Step must be greater than zero"); + Step = step; + } + + public StringBuilder AppendTo(StringBuilder builder) + { + return builder.Append('[') + .Append(_start) + .Append(':') + .Append(_end) + .Append(':') + .Append(Step) + .Append(']'); + } + + public override string ToString() + { + return AppendTo(new StringBuilder()).ToString(); + } + + public static ArraySliceSelector Parse(ReadOnlySpan selector) + { + if (selector.Length == 0) + throw new InvalidOperationException($"Invalid selector: {selector}"); + + var partIndex = 0; + var parts = new int?[3] {null, null, 1}; + + var subSelector = selector; + while (subSelector.Length > 0 && partIndex < parts.Length) + { + var nextIndex = subSelector.IndexOf(':'); + if (nextIndex == -1) + { + } + if (nextIndex > 0 && int.TryParse(subSelector[..nextIndex], out var parsedInt)) + parts[partIndex] = parsedInt; + partIndex++; + subSelector = subSelector[(nextIndex+1)..]; + } + if (subSelector.Length > 0) + throw new InvalidOperationException($"Invalid selector: {selector}"); + + return new ArraySliceSelector(parts[0], parts[1], parts[2]!.Value); + } + } + + public class ObjectPropertySelector : ISelector + { + public string PropertyName { get; } + + public ObjectPropertySelector(string propertyName) + { + PropertyName = propertyName; + } + + public ObjectPropertySelector(ReadOnlySpan propertyName) + { + PropertyName = propertyName.ToString(); + } + + public StringBuilder AppendTo(StringBuilder builder) + { + if (PropertyName.IndexOfAny(SpecialCharacters) != -1) + return builder.Append("['") + .Append(PropertyName) + .Append("']"); + + return builder.Append('.') + .Append(PropertyName); + } + + public override string ToString() + { + return AppendTo(new StringBuilder()).ToString(); + } + + public bool Equals(ObjectPropertySelector? other, StringComparison comparisonType = StringComparison.Ordinal) + { + if (other is null) + return false; + return string.Equals(PropertyName, other.PropertyName, comparisonType); + } + + public override bool Equals(object? obj) + { + if (obj is not ObjectPropertySelector other) + return false; + return Equals(other); + } + + public override int GetHashCode() + { + return base.GetHashCode(); + } + + private static readonly char[] SpecialCharacters = new char[18] { '.', ' ', '\'', '/', '"', '[', ']', '(', ')', '\t', '\n', '\r', '\f', '\b', '\\', '\u0085', '\u2028', '\u2029' }; + } +} diff --git a/src/Flattener/Extensions/TextJsonHelpers.cs b/src/Flattener/Extensions/TextJsonHelpers.cs new file mode 100644 index 0000000..dbe9343 --- /dev/null +++ b/src/Flattener/Extensions/TextJsonHelpers.cs @@ -0,0 +1,103 @@ +using System; +using System.Text.Json; +using System.Text.Json.Nodes; + +namespace CallRecordInsights.Extensions +{ + public static class TextJsonHelpers + { + /// + /// Gets the value of a JsonNode as a TimeSpan if it is a string in ISO 8601 duration or TimeSpan standard format. + /// + /// + /// + public static TimeSpan? GetValueAsTimeSpan(this JsonNode node) => + node is JsonValue + && (TryParseISO8601TimeSpan(node.GetValue(), out var tsv) + || TimeSpan.TryParse(node.GetValue(), out tsv)) + ? tsv + : null; + + /// + /// Gets the value of a JsonNode as a byte array if it is a base64 encoded string. + /// + /// + /// + public static byte[]? GetValueAsByteArray(this JsonNode node) => + node is JsonValue + && node.GetValue().TryGetBytesFromBase64(out var value) == true + ? value + : default; + + /// + /// Parses a string in ISO 8601 duration format to a TimeSpan. + /// + /// + /// + /// + public static bool TryParseISO8601TimeSpan(string? input, out TimeSpan time) + { + time = default; + + // Validate input + if (string.IsNullOrWhiteSpace(input) || !input.StartsWith('P') || input.Length == 1) + return false; + + // Initializing variables + int days = 0, hours = 0, minutes = 0; + double seconds = 0; + + // To avoid parsing the same part multiple times and to ensure the order of the parts + bool hasDays = false, hasTimePart = false, hasHours = false, hasMinutes = false, hasSeconds = false; + + int index = 1; // Start after 'P' + int timeIndex = -1; // Start of time part + while (index < input.Length) + { + char unit = input[index]; + switch (unit) + { + case 'D': + if (hasDays || hasTimePart || !int.TryParse(input.AsSpan(1, index - 1), out days)) + return false; + hasDays = true; + break; + case 'T': + if (hasTimePart) + return false; + hasTimePart = true; + timeIndex = index; + break; + case 'H': + if (!hasTimePart || hasHours || hasMinutes || hasSeconds || !int.TryParse(input.AsSpan(timeIndex + 1, index - timeIndex - 1), out hours) || hours > 24) + return false; + hasHours = true; + timeIndex = index; + break; + case 'M': + if (!hasTimePart || hasMinutes || hasSeconds || !int.TryParse(input.AsSpan(timeIndex + 1, index - timeIndex - 1), out minutes) || minutes > 60) + return false; + hasMinutes = true; + timeIndex = index; + break; + case 'S': + if (!hasTimePart || hasSeconds || !double.TryParse(input.AsSpan(timeIndex + 1, index - timeIndex - 1), out seconds) || seconds > 60d) + return false; + hasSeconds = true; + timeIndex = index; + break; + default: + if (!char.IsDigit(unit) && (!hasTimePart || hasSeconds || unit != '.')) + return false; + break; + } + + index++; + } + + // Assemble TimeSpan + time = new TimeSpan(days, hours, minutes, (int)seconds, (int)((seconds - (int)seconds) * 1000)); + return true; + } + } +} diff --git a/src/Flattener/FlattenerOptions.cs b/src/Flattener/FlattenerOptions.cs new file mode 100644 index 0000000..7fb8fe0 --- /dev/null +++ b/src/Flattener/FlattenerOptions.cs @@ -0,0 +1,11 @@ +using System.Collections.Generic; + +namespace CallRecordInsights.Flattener +{ + public class FlattenerOptions + { + public IDictionary? ColumnObjectMap { get; set; } + public IList? ColumnOrder { get; set; } + public bool CaseInsensitivePropertyNameMatching { get; set; } = false; + } +} \ No newline at end of file diff --git a/src/Flattener/IJsonFlattenerConfiguration.cs b/src/Flattener/IJsonFlattenerConfiguration.cs new file mode 100644 index 0000000..374e1f3 --- /dev/null +++ b/src/Flattener/IJsonFlattenerConfiguration.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Text.Json.Nodes; + +namespace CallRecordInsights.Flattener +{ + public interface IJsonFlattenerConfiguration : IReadOnlyDictionary + { + JsonNodeOptions Options { get; } + StringComparison StringComparison { get; } + } +} \ No newline at end of file diff --git a/src/Flattener/IJsonProcessor.cs b/src/Flattener/IJsonProcessor.cs new file mode 100644 index 0000000..452d298 --- /dev/null +++ b/src/Flattener/IJsonProcessor.cs @@ -0,0 +1,11 @@ +using System.Collections.Generic; +using System.Text.Json.Nodes; + +namespace CallRecordInsights.Flattener +{ + public interface IJsonProcessor + { + IEnumerable> ProcessNode(JsonNode? jObject); + IEnumerable> ProcessNode(string jsonString); + } +} \ No newline at end of file diff --git a/src/Flattener/JsonFlattener.cs b/src/Flattener/JsonFlattener.cs new file mode 100644 index 0000000..eea39f0 --- /dev/null +++ b/src/Flattener/JsonFlattener.cs @@ -0,0 +1,144 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text.Json.Nodes; +using CallRecordInsights.Extensions; + +namespace CallRecordInsights.Flattener +{ + public class JsonFlattener : IJsonProcessor + { + private readonly IJsonFlattenerConfiguration _configuration; + public JsonFlattener(IJsonFlattenerConfiguration configuration) + { + ArgumentNullException.ThrowIfNull(configuration, nameof(configuration)); + _configuration = configuration; + } + + /// + /// Get a new row with all columns set to null + /// + /// + /// + private Dictionary GetNewRow(IDictionary? parent = default) + { + var row = new Dictionary(); + foreach (var kvp in _configuration) + { + if (parent != null && parent.TryGetValue(kvp.Key, out var value)) + { + row.Add(kvp.Key, value); + continue; + } + row.Add(kvp.Key, null); + } + return row; + } + + /// + /// Process the json string and return a list of dictionaries with the column names and values + /// + /// + /// + public IEnumerable> ProcessNode(string jsonString) + { + var jObject = JsonNode.Parse(jsonString, _configuration.Options); + return ProcessNode(jObject); + } + + /// + /// Process the json node and return a list of dictionaries with the column names and values + /// + /// + /// + public IEnumerable> ProcessNode(JsonNode? jObject) + { + if (jObject == null) + { + return Enumerable.Empty>(); + } + + var result = new List>(); + var expanded = new Dictionary>(); + var currentIndices = new Dictionary(); + foreach (var kvp in _configuration) + { + var columnName = kvp.Key; + var jsonPath = kvp.Value; + expanded[columnName] = jObject.SelectTokens(jsonPath).ToList(); + currentIndices[columnName] = 0; + } + + var expandableNodes = expanded.Where(kvp => _configuration[kvp.Key].IsExpandable()); + var MaxDepth = expandableNodes?.Max(kvp => kvp.Value.FirstOrDefault()?.GetPath().LevelsOfExpansion() ?? 0) ?? 0; + var LeafNodes = expandableNodes?.Where(kvp => kvp.Value.FirstOrDefault()?.GetPath().LevelsOfExpansion() == MaxDepth) + .ToList(); + if (LeafNodes is null || LeafNodes.Count == 0) + { + var row = GetNewRow(); + foreach (var column in expanded.Keys) + { + row[column] = expanded[column].FirstOrDefault(); + } + result.Add(row); + return result; + } + var RowCount = LeafNodes.Max(kvp => kvp.Value?.Count ?? 0); + var nonLeafKeys = expanded.Keys.Except(LeafNodes.Select(kvp => kvp.Key)).ToList(); + for (var i = 0; i < RowCount; i++) + { + var row = GetNewRow(); + var leafPath = string.Empty; + foreach (var leaf in LeafNodes) + { + JsonNode? value = default; + if (leaf.Value.Count == RowCount) + { + value = leaf.Value[i]; + currentIndices[leaf.Key] = i; + } + else if (leaf.Value.Count > 0) + { + for (var j = currentIndices[leaf.Key]; j < leaf.Value.Count; j++) + { + var path = leaf.Value[j]?.GetPath(); + if (path is null) + continue; + if (path.IsRelativeOf(leafPath)) + { + value = leaf.Value[j]; + currentIndices[leaf.Key] = j; + break; + } + } + } + + row[leaf.Key] = value; + + if (value != default && leafPath == string.Empty && leaf.Value.Count > 0) + { + leafPath = value.GetPath().ToJsonPath().ToString(); + } + } + // TODO: Move this out of the for loop RowCount + foreach (var column in nonLeafKeys) + { + for (var j = currentIndices[column]; j < expanded[column].Count; j++) + { + var path = expanded[column][j]?.GetPath(); + if (path is null) + continue; + if (path.IsRelativeOf(leafPath)) + { + row[column] = expanded[column][j]; + currentIndices[column] = j; + break; + } + } + } + result.Add(row); + } + return result; + } + } +} diff --git a/src/Flattener/JsonFlattenerConfiguration.cs b/src/Flattener/JsonFlattenerConfiguration.cs new file mode 100644 index 0000000..98bbf08 --- /dev/null +++ b/src/Flattener/JsonFlattenerConfiguration.cs @@ -0,0 +1,139 @@ +using CallRecordInsights.Extensions; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using System.Text.Json.Nodes; + +namespace CallRecordInsights.Flattener +{ + public class ConfigurationSorter : IComparer where T : IComparable + { + private readonly IList _sortedItems; + + public ConfigurationSorter(IList sortedItems) + { + _sortedItems = sortedItems ?? throw new ArgumentNullException(nameof(sortedItems)); + } + + public int Compare(T? x, T? y) + { + if (x == null && y == null) { return 0; } + if (x == null) { return -1; } + if (y == null) { return 1; } + + var xIndex = _sortedItems.IndexOf(x); + var yIndex = _sortedItems.IndexOf(y); + // if both are not found, use the default comparer + if (xIndex == -1 && yIndex == -1) + return x.CompareTo(y); + // if only one is found, it comes first + if (yIndex == -1) + return 1; + if (xIndex == -1) + return -1; + // if both are found, use the index + return xIndex.CompareTo(yIndex); + } + } + + public class JsonFlattenerConfiguration : IJsonFlattenerConfiguration + { + private readonly IDictionary _configuration; + + public JsonNodeOptions Options { get; } + + public StringComparison StringComparison { get; } + + public JsonFlattenerConfiguration(FlattenerOptions options) + { + ArgumentNullException.ThrowIfNull(options, nameof(options)); + ArgumentNullException.ThrowIfNull(options.ColumnObjectMap, nameof(options.ColumnObjectMap)); + _configuration = new SortedDictionary( + options.ColumnObjectMap, + new ConfigurationSorter( + options.ColumnOrder?.Count == options.ColumnObjectMap.Count + ? options.ColumnOrder + : options.ColumnObjectMap.Keys.ToList() + )); + StringComparison = options.CaseInsensitivePropertyNameMatching ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal; + Options = new JsonNodeOptions() + { + PropertyNameCaseInsensitive = options.CaseInsensitivePropertyNameMatching, + }; + ValidateConfiguration(); + } + + internal JsonFlattenerConfiguration(FlattenerOptions options, bool shouldValidate) + { + ArgumentNullException.ThrowIfNull(options, nameof(options)); + ArgumentNullException.ThrowIfNull(options.ColumnObjectMap, nameof(options.ColumnObjectMap)); + _configuration = new SortedDictionary( + options.ColumnObjectMap, + new ConfigurationSorter( + options.ColumnOrder?.Count == options.ColumnObjectMap.Count + ? options.ColumnOrder + : options.ColumnObjectMap.Keys.ToList() + )); + StringComparison = options.CaseInsensitivePropertyNameMatching ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal; + Options = new JsonNodeOptions() + { + PropertyNameCaseInsensitive = options.CaseInsensitivePropertyNameMatching, + }; + if (shouldValidate) + ValidateConfiguration(); + } + + /// + /// Validates the configuration to ensure that no multiple expandable paths exist that are not on the same path. + /// + /// + private void ValidateConfiguration() + { + var _configurationSelectorCache = _configuration.ToDictionary(kvp => kvp.Key, kvp => kvp.Value.ParseJsonPath()); + // if any possibleExpansions exist that are not on the same path, we have an invalid configuration, as Cartesian Products are not supported as of yet. + var possiblyExpandableValues = new HashSet(); + foreach (var kvp in _configurationSelectorCache) + { + var jsonPath = kvp.Value; + var parentPath = jsonPath.GetParentPathAsEnumerable(); + if (parentPath == null || !parentPath.Any()) + continue; + + if (jsonPath.IsExpandable()) + { + possiblyExpandableValues.Add(kvp.Key); + var expandsFrom = jsonPath.GetParentPathAsEnumerable(); + while (expandsFrom.IsExpandable()) + expandsFrom = expandsFrom.GetParentPathAsEnumerable(); + } + } + foreach (var exp in possiblyExpandableValues) + { + var expPath = _configurationSelectorCache[exp]; + var notAtRoot = expPath.GetParentPathAsEnumerable().LevelsOfExpansion() > 0; + if (possiblyExpandableValues.Any(exp2 => exp != exp2 + && !_configurationSelectorCache[exp2].GetCommonAncestorAsEnumerable(expPath, StringComparison).Any() + && (notAtRoot || _configurationSelectorCache[exp2].GetParentPathAsEnumerable().LevelsOfExpansion() > 0))) + throw new InvalidOperationException("Invalid configuration. All expandable paths must share the same common ancestor.\nCartesian Product is not supported at this time."); + } + } + + public string this[string key] => _configuration[key]; + + public IEnumerable Keys => _configuration.Keys; + + public IEnumerable Values => _configuration.Values; + + public int Count => _configuration.Count; + + public bool ContainsKey(string key) => _configuration.ContainsKey(key); + + public IEnumerator> GetEnumerator() => _configuration.GetEnumerator(); + + public bool TryGetValue(string key, [MaybeNullWhen(false)] out string value) => _configuration.TryGetValue(key, out value); + + IEnumerator IEnumerable.GetEnumerator() => _configuration.GetEnumerator(); + } +} diff --git a/src/Flattener/Models/IKustoCallRecord.cs b/src/Flattener/Models/IKustoCallRecord.cs new file mode 100644 index 0000000..d7de7ad --- /dev/null +++ b/src/Flattener/Models/IKustoCallRecord.cs @@ -0,0 +1,252 @@ +using System; + +namespace CallRecordInsights.Models +{ + public interface IKustoCallRecord + { + string CallRecordTenantIdContext { get; set; } + Guid? CallId { get; set; } + Guid? SessionId { get; set; } + string? StreamId { get; set; } + string? StreamDirection { get; set; } + string? MediaLabel { get; set; } + DateTimeOffset? CallStartTime { get; set; } + DateTimeOffset? CallEndTime { get; set; } + DateTimeOffset? SessionStartTime { get; set; } + DateTimeOffset? SessionEndTime { get; set; } + DateTimeOffset? LastModifiedDateTimeOffset { get; set; } + string? CallType { get; set; } + string? JoinWebUrl { get; set; } + string? VideoCodec { get; set; } + string? AudioCodec { get; set; } + bool? WasMediaBypassed { get; set; } + string? FailureStage { get; set; } + string? FailureReason { get; set; } + long? PacketUtilization { get; set; } + long? AverageBandwidthEstimate { get; set; } + TimeSpan? AverageJitter { get; set; } + TimeSpan? MaxJitter { get; set; } + TimeSpan? AverageRoundTripTime { get; set; } + TimeSpan? MaxRoundTripTime { get; set; } + TimeSpan? AverageAudioNetworkJitter { get; set; } + TimeSpan? MaxAudioNetworkJitter { get; set; } + double? AverageAudioDegradation { get; set; } + double? AveragePacketLossRate { get; set; } + double? MaxPacketLossRate { get; set; } + double? PostForwardErrorCorrectionPacketLossRate { get; set; } + double? AverageRatioOfConcealedSamples { get; set; } + double? MaxRatioOfConcealedSamples { get; set; } + double? LowVideoProcessingCapabilityRatio { get; set; } + double? AverageVideoFrameRate { get; set; } + double? AverageReceivedFrameRate { get; set; } + double? LowFrameRateRatio { get; set; } + double? AverageVideoPacketLossRate { get; set; } + double? AverageVideoFrameLossPercentage { get; set; } + string? Organizer_UserDisplayName { get; set; } + Guid? Organizer_UserId { get; set; } + Guid? Organizer_UserTenantId { get; set; } + string? Organizer_ApplicationInstanceDisplayName { get; set; } + Guid? Organizer_ApplicationInstanceId { get; set; } + Guid? Organizer_ApplicationInstanceTenantId { get; set; } + string? Organizer_GuestDisplayName { get; set; } + Guid? Organizer_GuestId { get; set; } + Guid? Organizer_GuestTenantId { get; set; } + string? Organizer_PhoneDisplayName { get; set; } + string? Organizer_PhoneId { get; set; } + Guid? Organizer_PhoneTenantId { get; set; } + string? Organizer_OnPremisesDisplayName { get; set; } + Guid? Organizer_OnPremisesId { get; set; } + Guid? Organizer_OnPremisesTenantId { get; set; } + string? Organizer_EncryptedDisplayName { get; set; } + Guid? Organizer_EncryptedId { get; set; } + Guid? Organizer_EncryptedTenantId { get; set; } + string? Organizer_AcsUserDisplayName { get; set; } + Guid? Organizer_AcsUserId { get; set; } + Guid? Organizer_AcsUserTenantId { get; set; } + string? Organizer_SpoolUserDisplayName { get; set; } + Guid? Organizer_SpoolUserId { get; set; } + Guid? Organizer_SpoolUserTenantId { get; set; } + string? Organizer_AcsApplicationInstanceDisplayName { get; set; } + Guid? Organizer_AcsApplicationInstanceId { get; set; } + Guid? Organizer_AcsApplicationInstanceTenantId { get; set; } + string? Organizer_SpoolApplicationInstanceDisplayName { get; set; } + Guid? Organizer_SpoolApplicationInstanceId { get; set; } + Guid? Organizer_SpoolApplicationInstanceTenantId { get; set; } + string? Callee_UserDisplayName { get; set; } + Guid? Callee_UserId { get; set; } + Guid? Callee_UserTenantId { get; set; } + string? Callee_ApplicationInstanceDisplayName { get; set; } + Guid? Callee_ApplicationInstanceId { get; set; } + Guid? Callee_ApplicationInstanceTenantId { get; set; } + string? Callee_GuestDisplayName { get; set; } + Guid? Callee_GuestId { get; set; } + Guid? Callee_GuestTenantId { get; set; } + string? Callee_PhoneDisplayName { get; set; } + string? Callee_PhoneId { get; set; } + Guid? Callee_PhoneTenantId { get; set; } + string? Callee_OnPremisesDisplayName { get; set; } + Guid? Callee_OnPremisesId { get; set; } + Guid? Callee_OnPremisesTenantId { get; set; } + string? Callee_EncryptedDisplayName { get; set; } + Guid? Callee_EncryptedId { get; set; } + Guid? Callee_EncryptedTenantId { get; set; } + string? Callee_AcsUserDisplayName { get; set; } + Guid? Callee_AcsUserId { get; set; } + Guid? Callee_AcsUserTenantId { get; set; } + string? Callee_SpoolUserDisplayName { get; set; } + Guid? Callee_SpoolUserId { get; set; } + Guid? Callee_SpoolUserTenantId { get; set; } + string? Callee_AcsApplicationInstanceDisplayName { get; set; } + Guid? Callee_AcsApplicationInstanceId { get; set; } + Guid? Callee_AcsApplicationInstanceTenantId { get; set; } + string? Callee_SpoolApplicationInstanceDisplayName { get; set; } + Guid? Callee_SpoolApplicationInstanceId { get; set; } + Guid? Callee_SpoolApplicationInstanceTenantId { get; set; } + string? Callee_EndpointType { get; set; } + string? Callee_ProductFamily { get; set; } + string? Callee_Platform { get; set; } + string? Callee_UserAgentHeaderValue { get; set; } + string? Callee_ServiceRole { get; set; } + string? Callee_ApplicationVersion { get; set; } + Guid? Callee_AzureAdAppId { get; set; } + Guid? Callee_CommunicationServiceId { get; set; } + string? Callee_ConnectionType { get; set; } + string? Callee_ReflexiveIPAddress { get; set; } + string? Callee_Subnet { get; set; } + string? Callee_IpAddress { get; set; } + string? Callee_MacAddress { get; set; } + long? Callee_LinkSpeed { get; set; } + string? Callee_NetworkTransportProtocol { get; set; } + int? Callee_Port { get; set; } + string? Callee_RelayIPAddress { get; set; } + int? Callee_RelayPort { get; set; } + string? Callee_DnsSuffix { get; set; } + string? Callee_TraceRouteHops { get; set; } + string? Callee_BSSID { get; set; } + string? Callee_WifiRadioType { get; set; } + string? Callee_WifiBand { get; set; } + int? Callee_WifiChannel { get; set; } + int? Callee_WifiSignalStrength { get; set; } + int? Callee_WifiBatteryCharge { get; set; } + string? Callee_WifiMicrosoftDriver { get; set; } + string? Callee_WifiMicrosoftDriverVersion { get; set; } + string? Callee_WifiVendorDriver { get; set; } + string? Callee_WifiVendorDriverVersion { get; set; } + string? Callee_CaptureDeviceName { get; set; } + string? Callee_CaptureDeviceDriver { get; set; } + string? Callee_RenderDeviceName { get; set; } + string? Callee_RenderDeviceDriver { get; set; } + double? Callee_SentSignalLevel { get; set; } + double? Callee_SentNoiseLevel { get; set; } + double? Callee_MicGlitchRate { get; set; } + double? Callee_ReceivedSignalLevel { get; set; } + double? Callee_ReceivedNoiseLevel { get; set; } + double? Callee_SpeakerGlitchRate { get; set; } + int? Callee_HowlingEventCount { get; set; } + double? Callee_InitialSignalLevelRootMeanSquare { get; set; } + double? Callee_DeviceGlitchEventRatio { get; set; } + double? Callee_DeviceClippingEventRatio { get; set; } + double? Callee_LowSpeechToNoiseEventRatio { get; set; } + double? Callee_CaptureNotFunctioningEventRatio { get; set; } + double? Callee_SentQualityEventRatio { get; set; } + double? Callee_LowSpeechLevelEventRatio { get; set; } + double? Callee_RenderNotFunctioningEventRatio { get; set; } + double? Callee_ReceivedQualityEventRatio { get; set; } + double? Callee_RenderZeroVolumeEventRatio { get; set; } + double? Callee_RenderMuteEventRatio { get; set; } + double? Callee_CpuInsufficentEventRatio { get; set; } + double? Callee_DelayEventRatio { get; set; } + double? Callee_BandwidthLowEventRatio { get; set; } + string? Callee_FeedbackRating { get; set; } + string? Callee_FeedbackText { get; set; } + string? Callee_FeedbackTokens { get; set; } + string? Caller_UserDisplayName { get; set; } + Guid? Caller_UserId { get; set; } + Guid? Caller_UserTenantId { get; set; } + string? Caller_ApplicationInstanceDisplayName { get; set; } + Guid? Caller_ApplicationInstanceId { get; set; } + Guid? Caller_ApplicationInstanceTenantId { get; set; } + string? Caller_GuestDisplayName { get; set; } + Guid? Caller_GuestId { get; set; } + Guid? Caller_GuestTenantId { get; set; } + string? Caller_PhoneDisplayName { get; set; } + string? Caller_PhoneId { get; set; } + Guid? Caller_PhoneTenantId { get; set; } + string? Caller_OnPremisesDisplayName { get; set; } + Guid? Caller_OnPremisesId { get; set; } + Guid? Caller_OnPremisesTenantId { get; set; } + string? Caller_EncryptedDisplayName { get; set; } + Guid? Caller_EncryptedId { get; set; } + Guid? Caller_EncryptedTenantId { get; set; } + string? Caller_AcsUserDisplayName { get; set; } + Guid? Caller_AcsUserId { get; set; } + Guid? Caller_AcsUserTenantId { get; set; } + string? Caller_SpoolUserDisplayName { get; set; } + Guid? Caller_SpoolUserId { get; set; } + Guid? Caller_SpoolUserTenantId { get; set; } + string? Caller_AcsApplicationInstanceDisplayName { get; set; } + Guid? Caller_AcsApplicationInstanceId { get; set; } + Guid? Caller_AcsApplicationInstanceTenantId { get; set; } + string? Caller_SpoolApplicationInstanceDisplayName { get; set; } + Guid? Caller_SpoolApplicationInstanceId { get; set; } + Guid? Caller_SpoolApplicationInstanceTenantId { get; set; } + string? Caller_EndpointType { get; set; } + string? Caller_ProductFamily { get; set; } + string? Caller_Platform { get; set; } + string? Caller_UserAgentHeaderValue { get; set; } + string? Caller_ServiceRole { get; set; } + string? Caller_ApplicationVersion { get; set; } + Guid? Caller_AzureAdAppId { get; set; } + Guid? Caller_CommunicationServiceId { get; set; } + string? Caller_ConnectionType { get; set; } + string? Caller_ReflexiveIPAddress { get; set; } + string? Caller_Subnet { get; set; } + string? Caller_IpAddress { get; set; } + string? Caller_MacAddress { get; set; } + long? Caller_LinkSpeed { get; set; } + string? Caller_NetworkTransportProtocol { get; set; } + int? Caller_Port { get; set; } + string? Caller_RelayIPAddress { get; set; } + int? Caller_RelayPort { get; set; } + string? Caller_DnsSuffix { get; set; } + string? Caller_TraceRouteHops { get; set; } + string? Caller_BSSID { get; set; } + string? Caller_WifiRadioType { get; set; } + string? Caller_WifiBand { get; set; } + int? Caller_WifiChannel { get; set; } + int? Caller_WifiSignalStrength { get; set; } + int? Caller_WifiBatteryCharge { get; set; } + string? Caller_WifiMicrosoftDriver { get; set; } + string? Caller_WifiMicrosoftDriverVersion { get; set; } + string? Caller_WifiVendorDriver { get; set; } + string? Caller_WifiVendorDriverVersion { get; set; } + string? Caller_CaptureDeviceName { get; set; } + string? Caller_CaptureDeviceDriver { get; set; } + string? Caller_RenderDeviceName { get; set; } + string? Caller_RenderDeviceDriver { get; set; } + double? Caller_SentSignalLevel { get; set; } + double? Caller_SentNoiseLevel { get; set; } + double? Caller_MicGlitchRate { get; set; } + double? Caller_ReceivedSignalLevel { get; set; } + double? Caller_ReceivedNoiseLevel { get; set; } + double? Caller_SpeakerGlitchRate { get; set; } + int? Caller_HowlingEventCount { get; set; } + double? Caller_InitialSignalLevelRootMeanSquare { get; set; } + double? Caller_DeviceGlitchEventRatio { get; set; } + double? Caller_DeviceClippingEventRatio { get; set; } + double? Caller_LowSpeechToNoiseEventRatio { get; set; } + double? Caller_CaptureNotFunctioningEventRatio { get; set; } + double? Caller_SentQualityEventRatio { get; set; } + double? Caller_LowSpeechLevelEventRatio { get; set; } + double? Caller_RenderNotFunctioningEventRatio { get; set; } + double? Caller_ReceivedQualityEventRatio { get; set; } + double? Caller_RenderZeroVolumeEventRatio { get; set; } + double? Caller_RenderMuteEventRatio { get; set; } + double? Caller_CpuInsufficentEventRatio { get; set; } + double? Caller_DelayEventRatio { get; set; } + double? Caller_BandwidthLowEventRatio { get; set; } + string? Caller_FeedbackRating { get; set; } + string? Caller_FeedbackText { get; set; } + string? Caller_FeedbackTokens { get; set; } + } +} \ No newline at end of file diff --git a/src/Flattener/Models/KustoCallRecord.cs b/src/Flattener/Models/KustoCallRecord.cs new file mode 100644 index 0000000..dd63d0b --- /dev/null +++ b/src/Flattener/Models/KustoCallRecord.cs @@ -0,0 +1,253 @@ +using System; + +namespace CallRecordInsights.Models +{ + public class KustoCallRecord : IKustoCallRecord + { + public const string DEFAULT_TENANTID_CONTEXT = "DEFAULT"; + public string CallRecordTenantIdContext { get; set; } = DEFAULT_TENANTID_CONTEXT; + public Guid? CallId { get; set; } + public Guid? SessionId { get; set; } + public string? StreamId { get; set; } + public string? StreamDirection { get; set; } + public string? MediaLabel { get; set; } + public DateTimeOffset? CallStartTime { get; set; } + public DateTimeOffset? CallEndTime { get; set; } + public DateTimeOffset? SessionStartTime { get; set; } + public DateTimeOffset? SessionEndTime { get; set; } + public DateTimeOffset? LastModifiedDateTimeOffset { get; set; } + public string? CallType { get; set; } + public string? JoinWebUrl { get; set; } + public string? VideoCodec { get; set; } + public string? AudioCodec { get; set; } + public bool? WasMediaBypassed { get; set; } + public string? FailureStage { get; set; } + public string? FailureReason { get; set; } + public long? PacketUtilization { get; set; } + public long? AverageBandwidthEstimate { get; set; } + public TimeSpan? AverageJitter { get; set; } + public TimeSpan? MaxJitter { get; set; } + public TimeSpan? AverageRoundTripTime { get; set; } + public TimeSpan? MaxRoundTripTime { get; set; } + public TimeSpan? AverageAudioNetworkJitter { get; set; } + public TimeSpan? MaxAudioNetworkJitter { get; set; } + public double? AverageAudioDegradation { get; set; } + public double? AveragePacketLossRate { get; set; } + public double? MaxPacketLossRate { get; set; } + public double? PostForwardErrorCorrectionPacketLossRate { get; set; } + public double? AverageRatioOfConcealedSamples { get; set; } + public double? MaxRatioOfConcealedSamples { get; set; } + public double? LowVideoProcessingCapabilityRatio { get; set; } + public double? AverageVideoFrameRate { get; set; } + public double? AverageReceivedFrameRate { get; set; } + public double? LowFrameRateRatio { get; set; } + public double? AverageVideoPacketLossRate { get; set; } + public double? AverageVideoFrameLossPercentage { get; set; } + public string? Organizer_UserDisplayName { get; set; } + public Guid? Organizer_UserId { get; set; } + public Guid? Organizer_UserTenantId { get; set; } + public string? Organizer_ApplicationInstanceDisplayName { get; set; } + public Guid? Organizer_ApplicationInstanceId { get; set; } + public Guid? Organizer_ApplicationInstanceTenantId { get; set; } + public string? Organizer_GuestDisplayName { get; set; } + public Guid? Organizer_GuestId { get; set; } + public Guid? Organizer_GuestTenantId { get; set; } + public string? Organizer_PhoneDisplayName { get; set; } + public string? Organizer_PhoneId { get; set; } + public Guid? Organizer_PhoneTenantId { get; set; } + public string? Organizer_OnPremisesDisplayName { get; set; } + public Guid? Organizer_OnPremisesId { get; set; } + public Guid? Organizer_OnPremisesTenantId { get; set; } + public string? Organizer_EncryptedDisplayName { get; set; } + public Guid? Organizer_EncryptedId { get; set; } + public Guid? Organizer_EncryptedTenantId { get; set; } + public string? Organizer_AcsUserDisplayName { get; set; } + public Guid? Organizer_AcsUserId { get; set; } + public Guid? Organizer_AcsUserTenantId { get; set; } + public string? Organizer_SpoolUserDisplayName { get; set; } + public Guid? Organizer_SpoolUserId { get; set; } + public Guid? Organizer_SpoolUserTenantId { get; set; } + public string? Organizer_AcsApplicationInstanceDisplayName { get; set; } + public Guid? Organizer_AcsApplicationInstanceId { get; set; } + public Guid? Organizer_AcsApplicationInstanceTenantId { get; set; } + public string? Organizer_SpoolApplicationInstanceDisplayName { get; set; } + public Guid? Organizer_SpoolApplicationInstanceId { get; set; } + public Guid? Organizer_SpoolApplicationInstanceTenantId { get; set; } + public string? Callee_UserDisplayName { get; set; } + public Guid? Callee_UserId { get; set; } + public Guid? Callee_UserTenantId { get; set; } + public string? Callee_ApplicationInstanceDisplayName { get; set; } + public Guid? Callee_ApplicationInstanceId { get; set; } + public Guid? Callee_ApplicationInstanceTenantId { get; set; } + public string? Callee_GuestDisplayName { get; set; } + public Guid? Callee_GuestId { get; set; } + public Guid? Callee_GuestTenantId { get; set; } + public string? Callee_PhoneDisplayName { get; set; } + public string? Callee_PhoneId { get; set; } + public Guid? Callee_PhoneTenantId { get; set; } + public string? Callee_OnPremisesDisplayName { get; set; } + public Guid? Callee_OnPremisesId { get; set; } + public Guid? Callee_OnPremisesTenantId { get; set; } + public string? Callee_EncryptedDisplayName { get; set; } + public Guid? Callee_EncryptedId { get; set; } + public Guid? Callee_EncryptedTenantId { get; set; } + public string? Callee_AcsUserDisplayName { get; set; } + public Guid? Callee_AcsUserId { get; set; } + public Guid? Callee_AcsUserTenantId { get; set; } + public string? Callee_SpoolUserDisplayName { get; set; } + public Guid? Callee_SpoolUserId { get; set; } + public Guid? Callee_SpoolUserTenantId { get; set; } + public string? Callee_AcsApplicationInstanceDisplayName { get; set; } + public Guid? Callee_AcsApplicationInstanceId { get; set; } + public Guid? Callee_AcsApplicationInstanceTenantId { get; set; } + public string? Callee_SpoolApplicationInstanceDisplayName { get; set; } + public Guid? Callee_SpoolApplicationInstanceId { get; set; } + public Guid? Callee_SpoolApplicationInstanceTenantId { get; set; } + public string? Callee_EndpointType { get; set; } + public string? Callee_ProductFamily { get; set; } + public string? Callee_Platform { get; set; } + public string? Callee_UserAgentHeaderValue { get; set; } + public string? Callee_ServiceRole { get; set; } + public string? Callee_ApplicationVersion { get; set; } + public Guid? Callee_AzureAdAppId { get; set; } + public Guid? Callee_CommunicationServiceId { get; set; } + public string? Callee_ConnectionType { get; set; } + public string? Callee_ReflexiveIPAddress { get; set; } + public string? Callee_Subnet { get; set; } + public string? Callee_IpAddress { get; set; } + public string? Callee_MacAddress { get; set; } + public long? Callee_LinkSpeed { get; set; } + public string? Callee_NetworkTransportProtocol { get; set; } + public int? Callee_Port { get; set; } + public string? Callee_RelayIPAddress { get; set; } + public int? Callee_RelayPort { get; set; } + public string? Callee_DnsSuffix { get; set; } + public string? Callee_TraceRouteHops { get; set; } + public string? Callee_BSSID { get; set; } + public string? Callee_WifiRadioType { get; set; } + public string? Callee_WifiBand { get; set; } + public int? Callee_WifiChannel { get; set; } + public int? Callee_WifiSignalStrength { get; set; } + public int? Callee_WifiBatteryCharge { get; set; } + public string? Callee_WifiMicrosoftDriver { get; set; } + public string? Callee_WifiMicrosoftDriverVersion { get; set; } + public string? Callee_WifiVendorDriver { get; set; } + public string? Callee_WifiVendorDriverVersion { get; set; } + public string? Callee_CaptureDeviceName { get; set; } + public string? Callee_CaptureDeviceDriver { get; set; } + public string? Callee_RenderDeviceName { get; set; } + public string? Callee_RenderDeviceDriver { get; set; } + public double? Callee_SentSignalLevel { get; set; } + public double? Callee_SentNoiseLevel { get; set; } + public double? Callee_MicGlitchRate { get; set; } + public double? Callee_ReceivedSignalLevel { get; set; } + public double? Callee_ReceivedNoiseLevel { get; set; } + public double? Callee_SpeakerGlitchRate { get; set; } + public int? Callee_HowlingEventCount { get; set; } + public double? Callee_InitialSignalLevelRootMeanSquare { get; set; } + public double? Callee_DeviceGlitchEventRatio { get; set; } + public double? Callee_DeviceClippingEventRatio { get; set; } + public double? Callee_LowSpeechToNoiseEventRatio { get; set; } + public double? Callee_CaptureNotFunctioningEventRatio { get; set; } + public double? Callee_SentQualityEventRatio { get; set; } + public double? Callee_LowSpeechLevelEventRatio { get; set; } + public double? Callee_RenderNotFunctioningEventRatio { get; set; } + public double? Callee_ReceivedQualityEventRatio { get; set; } + public double? Callee_RenderZeroVolumeEventRatio { get; set; } + public double? Callee_RenderMuteEventRatio { get; set; } + public double? Callee_CpuInsufficentEventRatio { get; set; } + public double? Callee_DelayEventRatio { get; set; } + public double? Callee_BandwidthLowEventRatio { get; set; } + public string? Callee_FeedbackRating { get; set; } + public string? Callee_FeedbackText { get; set; } + public string? Callee_FeedbackTokens { get; set; } + public string? Caller_UserDisplayName { get; set; } + public Guid? Caller_UserId { get; set; } + public Guid? Caller_UserTenantId { get; set; } + public string? Caller_ApplicationInstanceDisplayName { get; set; } + public Guid? Caller_ApplicationInstanceId { get; set; } + public Guid? Caller_ApplicationInstanceTenantId { get; set; } + public string? Caller_GuestDisplayName { get; set; } + public Guid? Caller_GuestId { get; set; } + public Guid? Caller_GuestTenantId { get; set; } + public string? Caller_PhoneDisplayName { get; set; } + public string? Caller_PhoneId { get; set; } + public Guid? Caller_PhoneTenantId { get; set; } + public string? Caller_OnPremisesDisplayName { get; set; } + public Guid? Caller_OnPremisesId { get; set; } + public Guid? Caller_OnPremisesTenantId { get; set; } + public string? Caller_EncryptedDisplayName { get; set; } + public Guid? Caller_EncryptedId { get; set; } + public Guid? Caller_EncryptedTenantId { get; set; } + public string? Caller_AcsUserDisplayName { get; set; } + public Guid? Caller_AcsUserId { get; set; } + public Guid? Caller_AcsUserTenantId { get; set; } + public string? Caller_SpoolUserDisplayName { get; set; } + public Guid? Caller_SpoolUserId { get; set; } + public Guid? Caller_SpoolUserTenantId { get; set; } + public string? Caller_AcsApplicationInstanceDisplayName { get; set; } + public Guid? Caller_AcsApplicationInstanceId { get; set; } + public Guid? Caller_AcsApplicationInstanceTenantId { get; set; } + public string? Caller_SpoolApplicationInstanceDisplayName { get; set; } + public Guid? Caller_SpoolApplicationInstanceId { get; set; } + public Guid? Caller_SpoolApplicationInstanceTenantId { get; set; } + public string? Caller_EndpointType { get; set; } + public string? Caller_ProductFamily { get; set; } + public string? Caller_Platform { get; set; } + public string? Caller_UserAgentHeaderValue { get; set; } + public string? Caller_ServiceRole { get; set; } + public string? Caller_ApplicationVersion { get; set; } + public Guid? Caller_AzureAdAppId { get; set; } + public Guid? Caller_CommunicationServiceId { get; set; } + public string? Caller_ConnectionType { get; set; } + public string? Caller_ReflexiveIPAddress { get; set; } + public string? Caller_Subnet { get; set; } + public string? Caller_IpAddress { get; set; } + public string? Caller_MacAddress { get; set; } + public long? Caller_LinkSpeed { get; set; } + public string? Caller_NetworkTransportProtocol { get; set; } + public int? Caller_Port { get; set; } + public string? Caller_RelayIPAddress { get; set; } + public int? Caller_RelayPort { get; set; } + public string? Caller_DnsSuffix { get; set; } + public string? Caller_TraceRouteHops { get; set; } + public string? Caller_BSSID { get; set; } + public string? Caller_WifiRadioType { get; set; } + public string? Caller_WifiBand { get; set; } + public int? Caller_WifiChannel { get; set; } + public int? Caller_WifiSignalStrength { get; set; } + public int? Caller_WifiBatteryCharge { get; set; } + public string? Caller_WifiMicrosoftDriver { get; set; } + public string? Caller_WifiMicrosoftDriverVersion { get; set; } + public string? Caller_WifiVendorDriver { get; set; } + public string? Caller_WifiVendorDriverVersion { get; set; } + public string? Caller_CaptureDeviceName { get; set; } + public string? Caller_CaptureDeviceDriver { get; set; } + public string? Caller_RenderDeviceName { get; set; } + public string? Caller_RenderDeviceDriver { get; set; } + public double? Caller_SentSignalLevel { get; set; } + public double? Caller_SentNoiseLevel { get; set; } + public double? Caller_MicGlitchRate { get; set; } + public double? Caller_ReceivedSignalLevel { get; set; } + public double? Caller_ReceivedNoiseLevel { get; set; } + public double? Caller_SpeakerGlitchRate { get; set; } + public int? Caller_HowlingEventCount { get; set; } + public double? Caller_InitialSignalLevelRootMeanSquare { get; set; } + public double? Caller_DeviceGlitchEventRatio { get; set; } + public double? Caller_DeviceClippingEventRatio { get; set; } + public double? Caller_LowSpeechToNoiseEventRatio { get; set; } + public double? Caller_CaptureNotFunctioningEventRatio { get; set; } + public double? Caller_SentQualityEventRatio { get; set; } + public double? Caller_LowSpeechLevelEventRatio { get; set; } + public double? Caller_RenderNotFunctioningEventRatio { get; set; } + public double? Caller_ReceivedQualityEventRatio { get; set; } + public double? Caller_RenderZeroVolumeEventRatio { get; set; } + public double? Caller_RenderMuteEventRatio { get; set; } + public double? Caller_CpuInsufficentEventRatio { get; set; } + public double? Caller_DelayEventRatio { get; set; } + public double? Caller_BandwidthLowEventRatio { get; set; } + public string? Caller_FeedbackRating { get; set; } + public string? Caller_FeedbackText { get; set; } + public string? Caller_FeedbackTokens { get; set; } + } +} diff --git a/src/Functions/CallRecordInsights.Functions.csproj b/src/Functions/CallRecordInsights.Functions.csproj new file mode 100644 index 0000000..4aaee52 --- /dev/null +++ b/src/Functions/CallRecordInsights.Functions.csproj @@ -0,0 +1,57 @@ + + + + net6.0 + v4 + <_FunctionsSkipCleanOutput>true + + + + + + + + + true + + + + true + + + true + + + true + + + + + + + + + + + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + Never + + + PreserveNewest + Never + + + + + + + + diff --git a/src/Functions/Extensions/GraphRequestBuilderAppOnlyExtensions.cs b/src/Functions/Extensions/GraphRequestBuilderAppOnlyExtensions.cs new file mode 100644 index 0000000..2bd1702 --- /dev/null +++ b/src/Functions/Extensions/GraphRequestBuilderAppOnlyExtensions.cs @@ -0,0 +1,33 @@ +using Microsoft.Identity.Web; +using Microsoft.Kiota.Abstractions; +using System.Collections.Generic; +using System.Linq; + +namespace CallRecordInsights.Extensions +{ + public static class GraphRequestBuilderAppOnlyExtensions + { + /// + /// Specifies to use app only permissions for Graph. + /// + /// Options to modify. + /// Should the permissions be app only or not. + /// Tenant ID or domain for which we want to make the call.. + /// + public static IList AsAppForTenant(this IList options, string tenant = null) + { + var graphAuthenticationOptions = options.OfType().FirstOrDefault(); + if (graphAuthenticationOptions == null) + { + graphAuthenticationOptions = new GraphAuthenticationOptions(); + options.Add(graphAuthenticationOptions); + } + graphAuthenticationOptions.RequestAppToken = true; + graphAuthenticationOptions.AcquireTokenOptions ??= new(); + + graphAuthenticationOptions.AcquireTokenOptions.Tenant = tenant?.TryGetValidTenantIdGuid(out var tenantIdGuid) == true ? tenantIdGuid.ToString() : null; + + return options; + } + } +} diff --git a/src/Functions/Extensions/LoggingExtensions.cs b/src/Functions/Extensions/LoggingExtensions.cs new file mode 100644 index 0000000..ccb66e2 --- /dev/null +++ b/src/Functions/Extensions/LoggingExtensions.cs @@ -0,0 +1,22 @@ +using System.Web; + +namespace CallRecordInsights.Extensions +{ + public static class LoggingExtensions + { + /// + /// Sanitize the string to log by replacing tabs, new lines and carriage returns with underscores + /// + /// + /// + public static string Sanitize(this string stringToLog) + { + return HttpUtility.HtmlEncode( + stringToLog? + .Replace('\t','_') + .Replace('\r','_') + .Replace('\n','_') + ?? string.Empty); + } + } +} diff --git a/src/Functions/Extensions/ServiceCollectionExtensions.cs b/src/Functions/Extensions/ServiceCollectionExtensions.cs new file mode 100644 index 0000000..3527447 --- /dev/null +++ b/src/Functions/Extensions/ServiceCollectionExtensions.cs @@ -0,0 +1,210 @@ +using Azure.Core; +using Azure.Identity; +using CallRecordInsights.Flattener; +using CallRecordInsights.Models; +using CallRecordInsights.Services; +using Microsoft.Azure.Cosmos; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using Microsoft.Graph; +using Microsoft.Identity.Abstractions; +using Microsoft.Identity.Web; +using Microsoft.Kiota.Abstractions.Authentication; +using System; +using System.Collections.Generic; +using System.Linq; + +namespace CallRecordInsights.Extensions +{ + public static class ServiceCollectionExtensions + { + /// + /// Adds the with the default configuration for to the service collection. + /// + /// + /// + public static IServiceCollection AddJsonToKustoFlattener(this IServiceCollection services) + { + services.AddSingleton(serviceProvider => IKustoCallRecordHelpers.DefaultConfiguration); + services.AddSingleton(); + return services; + } + + /// + /// Adds the to the service collection. + /// + /// + /// + /// + public static IServiceCollection AddCallRecordsGraphContext( + this IServiceCollection services, + string sectionName = "GraphSubscription") + { + return services.AddMicrosoftGraphAsApplication() + .AddScoped(serviceProvider => new CallRecordsGraphOptions( + serviceProvider.GetRequiredService().GetSection(sectionName))) + .AddScoped(); + } + + /// + /// Adds the to the service collection. + /// + /// + /// + /// + public static IServiceCollection AddCallRecordsDataContext( + this IServiceCollection services, + string sectionName = "CallRecordInsightsDb") + { + return services + .AddSingleton(serviceProvider => + new CallRecordsDataContext( + new DefaultAzureCredential(), + serviceProvider.GetRequiredService().GetSection(sectionName), + serviceProvider.GetRequiredService>()) + ); + } + + + /// + /// Adds the to the service collection using the . + /// + /// + /// + /// + public static IServiceCollection AddMicrosoftGraphAsApplication( + this IServiceCollection services, + string sectionName = "AzureAd") + { + return services + .AddTokenCredential(sectionName) + .AddAzureMultiTenantGraphAuthenticationProvider() + .AddScoped(sp => new GraphServiceClient(sp.GetRequiredService())); + } + + + /// + /// Adds the to the service collection. + /// + /// + /// + public static IServiceCollection AddAzureMultiTenantGraphAuthenticationProvider(this IServiceCollection services) + { + return services + .AddScoped(); + } + + + /// + /// Adds the to the service collection using the + /// and for the + /// and for the . + /// + /// + /// + /// + /// + public static IServiceCollection AddTokenCredential(this IServiceCollection services, string sectionName) + { + var identityOptions = services.BuildServiceProvider() + .GetRequiredService() + .GetSection(sectionName) + .Get(); + var tokenCredentials = new List(); + + var defaultAzureCredentialOptions = new DefaultAzureCredentialOptions + { + ManagedIdentityClientId = identityOptions?.UserAssignedManagedIdentityClientId, + TenantId = identityOptions?.TenantId, + }; + defaultAzureCredentialOptions.AdditionallyAllowedTenants.Add("*"); + + var clientCertificateCredentialOptions = new ClientCertificateCredentialOptions(); + clientCertificateCredentialOptions.AdditionallyAllowedTenants.Add("*"); + + var clientSecretCredentialOptions = new ClientSecretCredentialOptions(); + clientSecretCredentialOptions.AdditionallyAllowedTenants.Add("*"); + + var clientAssertionCredentialOptions = new ClientAssertionCredentialOptions(); + clientAssertionCredentialOptions.AdditionallyAllowedTenants.Add("*"); + +#if DEBUG + defaultAzureCredentialOptions.Diagnostics.IsLoggingEnabled = true; + defaultAzureCredentialOptions.Diagnostics.IsAccountIdentifierLoggingEnabled = true; + + clientCertificateCredentialOptions.Diagnostics.IsLoggingEnabled = true; + clientCertificateCredentialOptions.Diagnostics.IsAccountIdentifierLoggingEnabled = true; + + clientSecretCredentialOptions.Diagnostics.IsLoggingEnabled = true; + clientSecretCredentialOptions.Diagnostics.IsAccountIdentifierLoggingEnabled = true; + + clientAssertionCredentialOptions.Diagnostics.IsLoggingEnabled = true; + clientAssertionCredentialOptions.Diagnostics.IsAccountIdentifierLoggingEnabled = true; +#endif + + DefaultCertificateLoader.UserAssignedManagedIdentityClientId = identityOptions?.UserAssignedManagedIdentityClientId; + + if (identityOptions?.ClientCredentials != null) + { + var credLoader = new DefaultCredentialsLoader(); + tokenCredentials.AddRange(identityOptions.ClientCredentials + .Where(c => credLoader.ShouldAddTokenCredential(c)) + .Select(c => + c.CredentialType switch + { + CredentialType.Certificate => + new ClientCertificateCredential(identityOptions.TenantId, identityOptions.ClientId, c.Certificate, clientCertificateCredentialOptions), + CredentialType.Secret => + new ClientSecretCredential(identityOptions.TenantId, identityOptions.ClientId, c.ClientSecret, clientSecretCredentialOptions), + CredentialType.SignedAssertion => + c.SourceType switch + { + CredentialSource.SignedAssertionFromManagedIdentity => + new ClientAssertionCredential(identityOptions.TenantId, identityOptions.ClientId, (c.CachedValue as ManagedIdentityClientAssertion).GetSignedAssertion, clientAssertionCredentialOptions), + CredentialSource.SignedAssertionFilePath => + new ClientAssertionCredential(identityOptions.TenantId, identityOptions.ClientId, (c.CachedValue as AzureIdentityForKubernetesClientAssertion).GetSignedAssertion, clientAssertionCredentialOptions), + CredentialSource.SignedAssertionFromVault => + new ClientAssertionCredential(identityOptions.TenantId, identityOptions.ClientId, (c.CachedValue as ClientAssertionProviderBase).GetSignedAssertion, clientAssertionCredentialOptions), + _ => throw new NotImplementedException(), + }, + _ => throw new NotImplementedException(), + })); + } + + if (identityOptions?.ClientCertificates != null) + { + var credLoader = new DefaultCertificateLoader(); + tokenCredentials.AddRange(identityOptions.ClientCertificates + .Where(c => credLoader.ShouldAddTokenCredential(c)) + .Select(c => new ClientCertificateCredential(identityOptions.TenantId, identityOptions.ClientId, c.Certificate))); + } + + tokenCredentials.Add(new DefaultAzureCredential(defaultAzureCredentialOptions)); + + return services.AddScoped(_ => new ChainedTokenCredential(tokenCredentials.ToArray())); + } + + internal static bool ShouldAddTokenCredential(this DefaultCredentialsLoader credentialsLoader, CredentialDescription credentialDescription) + { + if (credentialDescription.Skip || credentialDescription.CredentialType == CredentialType.DecryptKeys) return false; + try + { + credentialsLoader.LoadCredentialsIfNeededAsync(credentialDescription).GetAwaiter().GetResult(); + } + catch (Exception _) + when (_ is ArgumentException + || _ is NotSupportedException + || _ is InvalidOperationException + || _ is System.Security.Cryptography.CryptographicException + || _ is System.IO.IOException) + { + } + if (credentialDescription.Skip) return false; + if (credentialDescription.CredentialType == CredentialType.Secret) + return !string.IsNullOrEmpty(credentialDescription.ClientSecret); + + return credentialDescription.CachedValue is not null; + } + } +} diff --git a/src/Functions/Extensions/TenantIdValidator.cs b/src/Functions/Extensions/TenantIdValidator.cs new file mode 100644 index 0000000..4932ac5 --- /dev/null +++ b/src/Functions/Extensions/TenantIdValidator.cs @@ -0,0 +1,104 @@ +using System; +using System.Collections.Generic; +using System.Net.Http; +using System.Text.Json; +using System.Text.Json.Serialization; +using System.Threading.Tasks; + +namespace CallRecordInsights.Extensions +{ + public static class TenantIdValidator + { + public class OpenIdConfiguration + { + [JsonPropertyName("token_endpoint")] + public string TokenEndpoint { get; set; } + + public Guid GetTenantIdGuid() + { + if (string.IsNullOrEmpty(TokenEndpoint) + || !Uri.TryCreate(TokenEndpoint, UriKind.Absolute, out var uri) + || uri.Segments.Length < 2) + return Guid.Empty; + + var idSegment = uri.Segments[1][..^1]; // get the 2nd segment and remove the trailing slash + + if (Guid.TryParse(idSegment, out var id)) + return id; + + return Guid.Empty; + } + } + + private static readonly Dictionary cachedDomainLookups = new(); + private static readonly object cachedDomainLookupsLock = new(); + + private static readonly HttpClient httpClient = new( + new SocketsHttpHandler + { + PooledConnectionLifetime = TimeSpan.FromMinutes(15) + }); + + /// + /// Checks if the tenantId is a valid GUID or a valid domain name. + /// + /// + /// + public static bool IsValidTenantId(this string tenantId) => string.IsNullOrEmpty(tenantId) || Guid.TryParse(tenantId, out var _) || Uri.CheckHostName(tenantId) == UriHostNameType.Dns; + /// + /// Gets the tenant id GUID from the tenant id string if it is a valid Tenant Id. + /// + /// + /// + /// + public static bool TryGetValidTenantIdGuid(this string tenantIdString, out Guid tenantIdGuid) + { + tenantIdGuid = Guid.Empty; + if (string.IsNullOrEmpty(tenantIdString)) + return false; + + if (!IsValidTenantId(tenantIdString)) + return false; + + lock (cachedDomainLookupsLock) + if (cachedDomainLookups.TryGetValue(tenantIdString, out tenantIdGuid) && tenantIdGuid != Guid.Empty) + return true; + + // lookup the domain name to get the tenant id GUID + try + { + var data = GetOpenIdConfiguration(tenantIdString); + tenantIdGuid = data.GetTenantIdGuid(); + } + catch (Exception _) when (_ is ArgumentNullException or HttpRequestException or NullReferenceException or JsonException) + { + return false; + } + + lock (cachedDomainLookupsLock) + cachedDomainLookups[tenantIdString] = tenantIdGuid; + + return tenantIdGuid != Guid.Empty; + } + + /// + /// Get the OpenIdConfiguration for the tenantId in a synchronous manner. + /// + /// + /// + private static OpenIdConfiguration GetOpenIdConfiguration(string tenantId) => GetOpenIdConfigurationAsync(tenantId).GetAwaiter().GetResult(); + + /// + /// Get the OpenIdConfiguration for the tenantId. + /// + /// + /// + private static async Task GetOpenIdConfigurationAsync(string tenantId) + { + ArgumentNullException.ThrowIfNull(tenantId, nameof(tenantId)); + var response = await httpClient.GetAsync($"https://login.microsoftonline.com/{tenantId}/.well-known/openid-configuration"); + using var contentStream = await response.Content.ReadAsStreamAsync(); + return await JsonSerializer.DeserializeAsync(contentStream); + } + } +} diff --git a/src/Functions/Functions/AddOrRenewCallRecordsSubscriptionFunction.cs b/src/Functions/Functions/AddOrRenewCallRecordsSubscriptionFunction.cs new file mode 100644 index 0000000..5d27471 --- /dev/null +++ b/src/Functions/Functions/AddOrRenewCallRecordsSubscriptionFunction.cs @@ -0,0 +1,38 @@ +using CallRecordInsights.Services; +using Microsoft.Azure.WebJobs; +using Microsoft.Extensions.Logging; +using System; +using System.Threading; +using System.Threading.Tasks; + +namespace CallRecordInsights.Functions +{ + public class AddOrRenewCallRecordsSubscriptionFunction + { + private readonly ICallRecordsGraphContext callRecordsGraphContext; + private readonly ILogger logger; + + public AddOrRenewCallRecordsSubscriptionFunction( + ICallRecordsGraphContext callRecordsGraphContext, + ILogger logger) + { + this.callRecordsGraphContext = callRecordsGraphContext; + this.logger = logger; + } + + [FunctionName(nameof(AddOrRenewCallRecordsSubscriptionFunction))] + public async Task RunAsync( + [TimerTrigger("%RenewSubscriptionScheduleCron%")] + TimerInfo timerInfo, + CancellationToken cancellationToken = default) + { + logger?.LogInformation( + "{Function}.{Method} triggered at {DateTime}", + nameof(AddOrRenewCallRecordsSubscriptionFunction), + nameof(RunAsync), + DateTime.UtcNow); + + _ = await callRecordsGraphContext.AddOrRenewSubscriptionsForConfiguredTenantsAsync(cancellationToken); + } + } +} diff --git a/src/Functions/Functions/CallRecordsFunctionsAdmin.cs b/src/Functions/Functions/CallRecordsFunctionsAdmin.cs new file mode 100644 index 0000000..d1497b0 --- /dev/null +++ b/src/Functions/Functions/CallRecordsFunctionsAdmin.cs @@ -0,0 +1,243 @@ +using Azure; +using Azure.Storage.Queues; +using CallRecordInsights.Extensions; +using CallRecordInsights.Services; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Azure.WebJobs; +using Microsoft.Azure.WebJobs.Extensions.Http; +using Microsoft.Extensions.Logging; +using Microsoft.Graph; +using Microsoft.Graph.Models; +using Microsoft.Graph.Models.ODataErrors; +using System; +using System.Collections.Generic; +using System.Text.Json; +using System.Threading; +using System.Threading.Tasks; + +namespace CallRecordInsights.Functions +{ + public class CallRecordsFunctionsAdmin + { + private readonly ICallRecordsGraphContext callRecordsGraphContext; + private readonly ILogger logger; + + public CallRecordsFunctionsAdmin( + ICallRecordsGraphContext callRecordsGraphContext, + ILogger logger) + { + this.callRecordsGraphContext = callRecordsGraphContext; + this.logger = logger; + } + + [FunctionName(nameof(GetSubscriptionIdFunction))] + public async Task GetSubscriptionIdFunction( + [HttpTrigger(AuthorizationLevel.Admin, "get", Route = "subscription/{tenantId?}")] + HttpRequest request, + string tenantId = null, + CancellationToken cancellationToken = default) + { + logger?.LogInformation( + "{Function}.{Method} triggered at {DateTime}", + nameof(CallRecordsFunctionsAdmin), + nameof(GetSubscriptionIdFunction), + DateTime.UtcNow); + + using var cancellationSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, request.HttpContext.RequestAborted); + + try + { + var currentSubscription = await callRecordsGraphContext.GetSubscriptionForTenantAsync( + tenantId, + cancellationSource.Token) + .ConfigureAwait(false); + + if (currentSubscription is null) + { + return new NotFoundObjectResult(new ProblemDetails + { + Title = "Subscription not found.", + Detail = "The subscription for call records for this function was not found." + }); + } + return GetSubscriptionResult(currentSubscription, tenantId); + } + catch (ArgumentException ex) when (ex.Message?.Contains("not configured",StringComparison.OrdinalIgnoreCase) == true) + { + return new BadRequestObjectResult(new ProblemDetails + { + Title = "Tenant not configured.", + Detail = $"Could not find tenant \"{tenantId}\" in configuration." + }); + } + } + + [FunctionName(nameof(AddSubscriptionOrRenewIfExpiredFunction))] + public async Task AddSubscriptionOrRenewIfExpiredFunction( + [HttpTrigger(AuthorizationLevel.Admin, "put", "post", Route = "subscription/{tenantId?}")] + HttpRequest request, + string tenantId = null, + CancellationToken cancellationToken = default) + { + logger?.LogInformation( + "{Function}.{Method} triggered at {DateTime}", + nameof(CallRecordsFunctionsAdmin), + nameof(AddSubscriptionOrRenewIfExpiredFunction), + DateTime.UtcNow); + + logger?.LogInformation( + "Request received for {Tenant}", + string.IsNullOrEmpty(tenantId) ? "default tenant" : tenantId?.Sanitize()); + + using var cancellationSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, request.HttpContext.RequestAborted); + + try + { + var subscription = await callRecordsGraphContext.AddOrRenewSubscriptionsForTenantAsync( + tenantId, + cancellationSource.Token) + .ConfigureAwait(false); + + return GetSubscriptionResult(subscription, tenantId); + } + catch (ArgumentException ex) when (ex.Message?.Contains("not configured", StringComparison.OrdinalIgnoreCase) == true) + { + return new BadRequestObjectResult(new ProblemDetails + { + Title = "Tenant not configured.", + Detail = $"Could not find tenant \"{tenantId}\" in configuration." + }); + } + catch (ArgumentException ex) + { + return new BadRequestObjectResult(new ProblemDetails + { + Title = "Invalid request.", + Detail = ex.Message + }); + } + catch (ODataError ex) when (ex.Error?.Code?.Equals(GraphErrorCode.AccessDenied.ToString(), StringComparison.OrdinalIgnoreCase) == true) + { + return new UnauthorizedObjectResult(new ProblemDetails + { + Title = "Access denied.", + Detail = "The application does not have the required permissions to create a subscription for this tenant." + }); + } + } + + [FunctionName(nameof(ManuallyProcessCallIdsFunction))] + public async Task ManuallyProcessCallIdsFunction( + [HttpTrigger(AuthorizationLevel.Function, "post", Route = "callRecords")] + HttpRequest request, + [Queue("%CallRecordsToDownloadQueueName%", Connection = "CallRecordsQueueConnection")] + QueueClient callRecordsToDownloadQueue, + CancellationToken cancellationToken = default) + { + logger?.LogInformation( + "{Function}.{Method} triggered at {DateTime}", + nameof(CallRecordsFunctionsAdmin), + nameof(ManuallyProcessCallIdsFunction), + DateTime.UtcNow); + + using var cancellationSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, request.HttpContext.RequestAborted); + + IEnumerable callIds; + try + { + callIds = await request.ReadFromJsonAsync>(cancellationSource.Token); + } + catch (Exception ex) when (ex is JsonException or ArgumentNullException or NotSupportedException) + { + return new BadRequestObjectResult(new ProblemDetails + { + Title = "Invalid request body.", + Detail = "The request body was not a valid JSON array of callId Guids." + }); + } + + var results = new MultipleCallIdRequestResultObject(); + results.ProcessingSkippedDueToFailure.UnionWith(callIds); + foreach (var callId in results.ProcessingSkippedDueToFailure) + { + logger?.LogInformation( + "Manually process callRecord request received for callId: {callId}", + callId?.Sanitize()); + + results.ProcessingSkippedDueToFailure.Remove(callId); + if (!Guid.TryParse(callId, out var callIdGuid)) + { + results.QueuingFailure.Add(callId); + continue; + } + try + { + var reciept = await callRecordsToDownloadQueue.SendMessageAsync( + callIdGuid.ToString(), + cancellationSource.Token) + .ConfigureAwait(false); + + if (reciept?.Value is not null) + { + results.Queued.Add(callId); + continue; + } + + results.QueuingFailure.Add(callId); + } + catch(Exception ex) when (ex is RequestFailedException or TaskCanceledException or OperationCanceledException) + { + results.QueuingFailure.Add(callId); + } + } + return MultipleCallIdRequestResultObject.Result(results); + } + + /// + /// Converts a object to an object with appropriate fields. + /// + /// The to return + /// The TenantId requested + /// + private static IActionResult GetSubscriptionResult(Subscription subscription, string TenantId = null) + { + TenantId = string.IsNullOrEmpty(TenantId) ? "Default" : TenantId?.TryGetValidTenantIdGuid(out var tenantIdGuid) == true ? tenantIdGuid.ToString() : TenantId; + return new OkObjectResult( + new + { + subscription.Id, + subscription.ExpirationDateTime, + TenantId, + subscription.Resource, + subscription.ChangeType, + subscription.NotificationUrl, + }); + } + + public class MultipleCallIdRequestResultObject + { + public HashSet Queued { get; set; } = new(); + public HashSet QueuingFailure { get; set; } = new(); + public HashSet ProcessingSkippedDueToFailure { get; set; } = new(); + + /// + /// Wraps the in an with appropriate status code. + /// + /// + /// + public static ObjectResult Result(MultipleCallIdRequestResultObject results) + { + var code = results.QueuingFailure.Count + results.ProcessingSkippedDueToFailure.Count > 0 + ? results.Queued.Count == 0 + ? StatusCodes.Status500InternalServerError + : StatusCodes.Status207MultiStatus + : StatusCodes.Status200OK; + return new ObjectResult(results) + { + StatusCode = code + }; + } + } + } +} diff --git a/src/Functions/Functions/GetCallRecordAdminFunction.cs b/src/Functions/Functions/GetCallRecordAdminFunction.cs new file mode 100644 index 0000000..0d3e50e --- /dev/null +++ b/src/Functions/Functions/GetCallRecordAdminFunction.cs @@ -0,0 +1,113 @@ +using CallRecordInsights.Extensions; +using CallRecordInsights.Services; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Azure.WebJobs; +using Microsoft.Azure.WebJobs.Extensions.Http; +using Microsoft.Extensions.Logging; +using Microsoft.Kiota.Abstractions; +using System; +using System.Threading; +using System.Threading.Tasks; + +namespace CallRecordInsights.Functions.Functions +{ + public class GetCallRecordAdminFunction + { + private readonly ICallRecordsGraphContext callRecordsGraphContext; + private readonly ILogger logger; + + public GetCallRecordAdminFunction( + ICallRecordsGraphContext callRecordsGraphContext, + ILogger logger) + { + this.callRecordsGraphContext = callRecordsGraphContext; + this.logger = logger; + } + + [FunctionName(nameof(GetCallRecordAdminFunction))] + public async Task RunAsync( + [HttpTrigger(AuthorizationLevel.Admin, "get", Route = "callRecords/{callId}/{tenantId?}")] + HttpRequest request, + Guid callId, + string tenantId = null, + CancellationToken cancellationToken = default) + { + logger?.LogInformation( + "{Function}.{Method} triggered at {DateTime}", + nameof(GetCallRecordAdminFunction), + nameof(RunAsync), + DateTime.UtcNow); + + using var cancellationSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, request.HttpContext.RequestAborted); + if (!string.IsNullOrEmpty(tenantId)) + { + try + { + var record = await callRecordsGraphContext.GetCallRecordFromTenantAsync( + callId.ToString(), + tenantId, + cancellationSource.Token, + logNotFoundErrors: true) + .ConfigureAwait(false); + + var callRecordString = await record.SerializeAsStringAsync().ConfigureAwait(false); + + return new ContentResult() + { + Content = callRecordString, + ContentType = "application/json", + StatusCode = StatusCodes.Status200OK, + }; + } + catch (ApiException ex) when (ex.ResponseStatusCode == (int)System.Net.HttpStatusCode.NotFound) + { + return new NotFoundObjectResult(new { error = new { message = $"Call Record Not Found for {callId} in tenant {tenantId}" } }); + } + catch (ApiException ex) + { + logger.LogError( + ex, + "Error getting call record from tenant {tenantId}", + tenantId); + + var result = new ObjectResult(new { error = new { message = $"Error getting call record {callId} from tenant {tenantId}" } }); + result.StatusCode = StatusCodes.Status500InternalServerError; + + return result; + } + catch (ArgumentException ex) when (ex.Message?.Contains("not configured", StringComparison.OrdinalIgnoreCase) == true) + { + logger.LogError( + ex, + "Error getting call record from tenant {tenantId}", + tenantId); + return new BadRequestObjectResult(new { error = new { message = $"Tenant {tenantId} is not configured" } }); + } + } + try + { + var allRecords = await callRecordsGraphContext.GetCallRecordFromConfiguredTenantsAsync( + callId.ToString(), + cancellationSource.Token) + .ConfigureAwait(false); + + var resultString = await allRecords.SerializeAsStringAsync().ConfigureAwait(false); + + return new ContentResult() + { + Content = resultString, + ContentType = "application/json", + StatusCode = StatusCodes.Status200OK, + }; + } + catch (Exception ex) when (ex is AggregateException or ApiException) + { + logger.LogError(ex, "Error getting call record from configured tenants"); + var result = new ObjectResult(new { error = new { message = $"Error getting call record from configured tenants" } }); + result.StatusCode = StatusCodes.Status500InternalServerError; + return result; + } + } + } +} diff --git a/src/Functions/Functions/GetCallRecordInsightsHealthFunction.cs b/src/Functions/Functions/GetCallRecordInsightsHealthFunction.cs new file mode 100644 index 0000000..15c6ebb --- /dev/null +++ b/src/Functions/Functions/GetCallRecordInsightsHealthFunction.cs @@ -0,0 +1,237 @@ +using Azure; +using Azure.Storage.Queues; +using CallRecordInsights.Services; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Azure.WebJobs; +using Microsoft.Azure.WebJobs.Extensions.Http; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Logging; +using Microsoft.Graph.Models; +using Microsoft.Kiota.Abstractions; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net.Http; +using System.Net.Sockets; +using System.Threading; +using System.Threading.Tasks; + +namespace CallRecordInsights.Functions +{ + public class GetCallRecordInsightsHealthFunction + { + private readonly ILogger logger; + private readonly IConfiguration configuration; + private readonly ICallRecordsGraphContext callRecordsGraphContext; + private readonly ICallRecordsDataContext callRecordsDataContext; + private readonly string eventHubName; + + public GetCallRecordInsightsHealthFunction( + ICallRecordsGraphContext callRecordsGraphContext, + ICallRecordsDataContext callRecordsDataContext, + IConfiguration configuration, + ILogger logger) + { + this.callRecordsGraphContext = callRecordsGraphContext; + this.callRecordsDataContext = callRecordsDataContext; + this.configuration = configuration; + this.logger = logger; + eventHubName = configuration.GetValue("GraphNotificationEventHubName"); + } + + [FunctionName(nameof(GetCallRecordInsightsHealthFunction))] + public async Task RunAsync( + [HttpTrigger(AuthorizationLevel.Admin, "get", Route = "health")] + HttpRequest request, + [Queue("%CallRecordsToDownloadQueueName%", Connection = "CallRecordsQueueConnection")] + QueueClient callRecordsToDownloadQueue, + CancellationToken cancellationToken = default) + { + logger?.LogInformation( + "{Function}.{Method} triggered at {DateTime}", + nameof(GetCallRecordInsightsHealthFunction), + nameof(RunAsync), + DateTime.UtcNow); + + using var cancellationSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, request.HttpContext.RequestAborted); + + try + { + var EventHub = GetEventHubHealth(); + var Cosmos = await GetCosmosHealthAsync(cancellationSource.Token).ConfigureAwait(false); + var DownloadQueue = await GetQueueHealthAsync(callRecordsToDownloadQueue, cancellationSource.Token).ConfigureAwait(false); + + IDictionary subs = default; + try + { + subs = await callRecordsGraphContext.GetSubscriptionsFromConfiguredTenantsAsync(cancellationSource.Token) + .ConfigureAwait(false); + } + catch (Exception ex) when ( + ex is AggregateException or RequestFailedException + or ApiException or HttpRequestException + or SocketException or TimeoutException) + { + logger?.LogError(ex, "Error querying Subscriptions"); + } + + var Subscriptions = subs? + .Select(s => new + { + s.Value.Id, + s.Value.ExpirationDateTime, + TenantId = s.Key, + }) + .ToList(); + + var UnhealthyServices = new List(); + if (!EventHub.Healthy) + UnhealthyServices.Add(nameof(EventHub)); + if (!Cosmos.Healthy) + UnhealthyServices.Add(nameof(Cosmos)); + if (!DownloadQueue.Healthy) + UnhealthyServices.Add(nameof(DownloadQueue)); + if (Subscriptions is null || Subscriptions.Count != callRecordsGraphContext.Tenants.Count) + UnhealthyServices.Add(nameof(Subscriptions)); + + return new OkObjectResult( + new + { + Healthy = !UnhealthyServices.Any(), + EventHub, + Cosmos, + DownloadQueue, + Subscriptions, + UnhealthyServices, + }); + } + catch (Exception ex) when (ex is TaskCanceledException or OperationCanceledException) + { + return new StatusCodeResult(StatusCodes.Status503ServiceUnavailable); + } + } + + /// + /// Gets the value of a key from a connection string. + /// + /// The connection string to parse + /// The key to retrieve + /// The value of the in the if present + private static string GetValueFromConnectionString(string connectionString, string key) + { + const StringSplitOptions splitOptions = StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries; + return connectionString?.Split(';', splitOptions)?.FirstOrDefault(s => s.StartsWith(key))?.Split('=', 2, splitOptions)[1]; + } + + internal record HealthState + { + public bool Healthy; + public string Status; + public string Url; + } + + /// + /// Retrieves the configuration of the Event Hub, no connection is made. + /// + /// + private HealthState GetEventHubHealth() + { + var EventHub = new HealthState + { + Healthy = false, + Status = string.Empty, + Url = string.Empty, + }; + + if (string.IsNullOrEmpty(eventHubName)) + { + EventHub.Status = "No EventHub name found in configuration."; + return EventHub; + } + + var eventHubConfiguration = configuration.GetWebJobsConnectionSection("EventHubConnection"); + if (!eventHubConfiguration.Exists() || (string.IsNullOrEmpty(eventHubConfiguration.Value) && eventHubConfiguration["fullyQualifiedNamespace"] == null)) + { + EventHub.Status = "No EventHub connection string or fullyQualifiedNamespace found in configuration."; + return EventHub; + } + + EventHub.Healthy = true; + if (!string.IsNullOrEmpty(eventHubConfiguration.Value)) + { + EventHub.Url = $"{GetValueFromConnectionString(eventHubConfiguration.Value, "Endpoint").TrimEnd('/')}/{eventHubName}"; + return EventHub; + } + + EventHub.Url = $"sb://{eventHubConfiguration["fullyQualifiedNamespace"]}/{eventHubName}"; + return EventHub; + } + + /// + /// Gets the health of the Cosmos DB container by verifying it is accessible. + /// + /// + /// + private async Task GetCosmosHealthAsync(CancellationToken token) + { + if (callRecordsGraphContext is null) + { + return new HealthState + { + Healthy = false, + Status = "No CallRecordGraphContext found.", + }; + } + var isAccessible = await callRecordsDataContext.IsAccessible(token).ConfigureAwait(false); + if (!isAccessible) + { + return new HealthState + { + Healthy = false, + Status = "Cosmos DB is not accessible.", + Url = callRecordsDataContext.Endpoint, + }; + } + return new HealthState + { + Healthy = true, + Url = callRecordsDataContext.Endpoint, + }; + } + + /// + /// Gets the health of the Queue by peeking the next message. + /// + /// The to test + /// + /// + private async Task GetQueueHealthAsync(QueueClient queueClient, CancellationToken cancellationToken = default) + { + var Queue = new HealthState + { + Healthy = false, + Status = string.Empty, + Url = queueClient?.Uri?.ToString(), + }; + try + { + if (queueClient != null) + { + // Just make sure we don't throw an exception + _ = await queueClient.PeekMessagesAsync(1, cancellationToken).ConfigureAwait(false); + Queue.Healthy = true; + } + } + catch (Exception ex) when ( + ex is RequestFailedException + or SocketException or TimeoutException + or HttpRequestException) + { + logger?.LogError(ex, "Error querying Queue"); + Queue.Status = ex.Message; + } + return Queue; + } + } +} diff --git a/src/Functions/Functions/ProcessCallRecordFunction.cs b/src/Functions/Functions/ProcessCallRecordFunction.cs new file mode 100644 index 0000000..bba4d21 --- /dev/null +++ b/src/Functions/Functions/ProcessCallRecordFunction.cs @@ -0,0 +1,241 @@ +using Azure; +using CallRecordInsights.Extensions; +using CallRecordInsights.Flattener; +using CallRecordInsights.Models; +using CallRecordInsights.Services; +using Microsoft.Azure.Cosmos; +using Microsoft.Azure.WebJobs; +using Microsoft.Extensions.Logging; +using Microsoft.Graph.Models.CallRecords; +using Microsoft.Kiota.Abstractions; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; + +namespace CallRecordInsights.Functions +{ + public class ProcessCallRecordFunction + { + private readonly ICallRecordsGraphContext callRecordsGraphContext; + private readonly ICallRecordsDataContext callRecordsDataContext; + private readonly IJsonProcessor jsonFlattener; + private readonly ILogger logger; + + public ProcessCallRecordFunction( + ICallRecordsGraphContext callRecordsGraphContext, + ICallRecordsDataContext callRecordsDataContext, + IJsonProcessor jsonFlattener, + ILogger logger) + { + this.callRecordsGraphContext = callRecordsGraphContext; + this.callRecordsDataContext = callRecordsDataContext; + this.jsonFlattener = jsonFlattener; + this.logger = logger; + } + + [FunctionName(nameof(ProcessCallRecordFunction))] + public async Task RunAsync( + [QueueTrigger("%CallRecordsToDownloadQueueName%", Connection = "CallRecordsQueueConnection")] + string queuedCallId, + CancellationToken cancellationToken = default) + { + logger?.LogInformation( + "{Function}.{Method} triggered at {DateTime}", + nameof(ProcessCallRecordFunction), + nameof(RunAsync), + DateTime.UtcNow); + + var (tenantIdString, callIdString) = GetTenantIdAndCallId(queuedCallId); + + if (!Guid.TryParse(callIdString, out var callIdGuid)) + { + logger?.LogWarning( + "CallId '{QueuedCallId}' => '{CallId}' was not a valid Guid", + queuedCallId?.Sanitize(), + callIdString?.Sanitize()); + return; + } + + if (tenantIdString.TryGetValidTenantIdGuid(out var tenantIdGuid)) + { + try + { + var callRecord = await callRecordsGraphContext.GetCallRecordFromTenantAsync( + callIdGuid.ToString(), + tenantIdGuid.ToString(), + cancellationToken, + logNotFoundErrors: true) + .ConfigureAwait(false); + + await ProcessRecordAsync( + callRecord, + tenantIdString, + cancellationToken) + .ConfigureAwait(false); + } + catch (Exception ex) when ( + ex is AggregateException or RequestFailedException + or ApiException + or TaskCanceledException or OperationCanceledException + or CosmosException or InvalidOperationException) + { + logger?.LogError( + ex, + "Error Processing Record: {TenantId} {CallId}", + tenantIdGuid, + callIdGuid); + } + return; + } + + IDictionary allRecords; + try + { + allRecords = await callRecordsGraphContext.GetCallRecordFromConfiguredTenantsAsync( + callIdGuid.ToString(), + cancellationToken) + .ConfigureAwait(false); + } + catch (Exception ex) when ( + ex is AggregateException or RequestFailedException + or ApiException + or TaskCanceledException or OperationCanceledException) + { + logger?.LogError( + ex, + "Error Getting Record: {TenantId} {CallId}", + tenantIdGuid, + callIdGuid); + + throw; + } + + var allExceptions = new List(); + foreach (var record in allRecords) + { + try + { + await ProcessRecordAsync(record.Value, record.Key, cancellationToken).ConfigureAwait(false); + } + catch (Exception ex) when ( + ex is AggregateException or RequestFailedException + or TaskCanceledException or OperationCanceledException + or CosmosException or InvalidOperationException) + { + logger?.LogError( + ex, + "Error Processing Record: {TenantId} {CallId}", + record.Key, + callIdGuid); + + allExceptions.Add(ex); + } + } + + if (allExceptions.Count > 0) + throw new AggregateException(allExceptions); + } + + /// + /// Gets the tenantId and callId from the queuedCallId which is in the format of "tenantId|callId" + /// + /// + /// + private static (string tenantId, string callId) GetTenantIdAndCallId(string queuedCallId) + { + var tenantId = string.Empty; + var callId = queuedCallId; + if (queuedCallId.Contains('|')) + { + var callIdParts = queuedCallId.Split('|', StringSplitOptions.TrimEntries); + tenantId = callIdParts[0]; + callId = callIdParts[1]; + } + return (tenantId, callId); + } + + /// + /// Processes the in the context and upserts the records into Cosmos + /// + /// The to process + /// The TenantId context + /// + /// + /// + private async Task ProcessRecordAsync( + CallRecord callRecord, + string tenantId, + CancellationToken cancellationToken = default) + { + if (callRecord == null) + throw new ArgumentNullException(nameof(callRecord)); + if (tenantId == null) + throw new ArgumentNullException(nameof(tenantId)); + + try + { + var cosmosCallRecords = callRecord.AsKustoCallRecords( + jsonFlattener, + tenantId) + .Select(r => CosmosCallRecord.Create(r)) + .ToList(); + + if (cosmosCallRecords.Count == 0) + { + logger?.LogInformation( + "Skipping {CallId} {TenantId} as no records were generated", + callRecord.Id, + tenantId?.Sanitize()); + + return; + } + + var tenantIdContext = cosmosCallRecords.First().CallRecordTenantIdContext; + + var callId = cosmosCallRecords.First().CallId ?? Guid.Empty; + + var lastModified = cosmosCallRecords.Max(r => r.LastModifiedDateTimeOffset); + + var cosmosOperation = await callRecordsDataContext.GetNeededProcessedRecordsOperationAsync( + tenantIdContext, + callId, + lastModified, + cosmosCallRecords.Count, + cancellationToken) + .ConfigureAwait(false); + + if (cosmosOperation == CallRecordsDataContext.Operation.Skip) + { + logger?.LogInformation( + "Skipping {CallId} {TenantId}", + callId, + tenantIdContext, + lastModified); + return; + } + + await callRecordsDataContext.CreateOrUpsertProcessedRecordsAsync( + cosmosCallRecords, + tenantIdContext, + callId, + cosmosOperation, + cancellationToken) + .ConfigureAwait(false); + } + catch (Exception ex) when ( + ex is AggregateException or RequestFailedException + or TaskCanceledException or OperationCanceledException + or CosmosException or InvalidOperationException) + { + logger?.LogError( + ex, + "Upsert Failure for {CallId}", + callRecord.Id); + + throw; + } + } + } +} diff --git a/src/Functions/Functions/ProcessEventHubEventFunction.cs b/src/Functions/Functions/ProcessEventHubEventFunction.cs new file mode 100644 index 0000000..274bfea --- /dev/null +++ b/src/Functions/Functions/ProcessEventHubEventFunction.cs @@ -0,0 +1,162 @@ +using Azure; +using Azure.Core.Serialization; +using Azure.Messaging.EventHubs; +using Azure.Storage.Queues; +using CallRecordInsights.Models; +using Microsoft.Azure.WebJobs; +using Microsoft.Extensions.Logging; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text.Json; +using System.Threading; +using System.Threading.Tasks; + +namespace CallRecordInsights.Functions +{ + public class ProcessEventHubEventFunction + { + private readonly ILogger logger; + + public ProcessEventHubEventFunction( + ILogger logger) + { + this.logger = logger; + } + + [FunctionName(nameof(ProcessEventHubEventFunction))] + public async Task RunAsync( + [EventHubTrigger("%GraphNotificationEventHubName%", Connection = "EventHubConnection")] + EventData[] eventDataBatch, + [Queue("%CallRecordsToDownloadQueueName%", Connection = "CallRecordsQueueConnection")] + QueueClient callRecordsToDownloadQueue, + CancellationToken cancellationToken = default) + { + logger?.LogInformation( + "{Function}.{Method} triggered at {DateTime}", + nameof(ProcessEventHubEventFunction), + nameof(RunAsync), + DateTime.UtcNow); + + logger?.LogInformation( + "Trigger contains {EventCount} events", + eventDataBatch.Length); + + var exceptions = new List(); + foreach (var eventDataEntry in eventDataBatch) + { + try + { + logger?.LogInformation( + "Processing event {PartitionKey} {SequenceNumber} {EnqueuedTime}", + eventDataEntry.PartitionKey, + eventDataEntry.SequenceNumber, + eventDataEntry.EnqueuedTime); + + var notificationBatch = await eventDataEntry.EventBody + .ToObjectAsync( + JsonObjectSerializer.Default, + cancellationToken) + .ConfigureAwait(false); + + logger?.LogInformation( + "Event contains {NotificationCount} notifications", + notificationBatch?.Value?.Count()); + + foreach (var notification in notificationBatch?.Value) + { + if (notification.ResourceData is null || !notification.ResourceData.IsCallRecordEvent()) + { + logger?.LogInformation( + "Unwanted notification of type {ODataType}", + notification.ResourceData.ODataType); + continue; + } + + if (string.IsNullOrWhiteSpace(notification.ResourceData.Id)) + { + logger?.LogWarning( + "Invalid notification of type {ODataType}: id '{id}' was null or whitespace", + notification.ResourceData.ODataType, + notification.ResourceData.Id); + continue; + } + + await QueueNotificationForProcessingAsync( + notification, + callRecordsToDownloadQueue, + cancellationToken) + .ConfigureAwait(false); + } + } + catch (Exception ex) when (ex is FormatException or JsonException) + { + logger?.LogWarning( + ex, + "{PartitionKey} {SequenceNumber} {EnqueuedTime} is not a valid event", + eventDataEntry.PartitionKey, + eventDataEntry.SequenceNumber, + eventDataEntry.EnqueuedTime); + } + catch (Exception ex) when ( + ex is RequestFailedException + or NullReferenceException + or TaskCanceledException or OperationCanceledException) + { + logger?.LogError( + ex, + "Error processing event {PartitionKey} {SequenceNumber} {EnqueuedTime}", + eventDataEntry.PartitionKey, + eventDataEntry.SequenceNumber, + eventDataEntry.EnqueuedTime); + exceptions.Add(ex); + } + } + + if (exceptions.Count > 0) + throw new AggregateException("Error(s) processing Event Hub Data", exceptions); + } + + /// + /// Adds the notification to the queue for processing + /// + /// The to queue + /// The destination + /// + /// + private async Task QueueNotificationForProcessingAsync( + GraphEventNotification changeNotification, + QueueClient callRecordsToDownloadQueue, + CancellationToken cancellationToken = default) + { + var newEntity = new CosmosEventNotification(changeNotification); + try + { + logger?.LogInformation( + "Try Adding {id} to {Destination}", + newEntity.GetQueueString(), + callRecordsToDownloadQueue.Name); + + await callRecordsToDownloadQueue.SendMessageAsync( + newEntity.GetQueueString(), + cancellationToken) + .ConfigureAwait(false); + + logger?.LogInformation( + "Success Adding {id} to {Destination}", + newEntity.GetQueueString(), + callRecordsToDownloadQueue.Name); + } + catch (Exception ex) when (ex is RequestFailedException or TaskCanceledException or OperationCanceledException) + { + logger?.LogError( + ex, + "Error Adding {id} to {Destination}", + newEntity.GetQueueString(), + callRecordsToDownloadQueue.Name); + + throw; + } + } + } +} diff --git a/src/Functions/Models/CallRecordsGraphOptions.cs b/src/Functions/Models/CallRecordsGraphOptions.cs new file mode 100644 index 0000000..6046f7c --- /dev/null +++ b/src/Functions/Models/CallRecordsGraphOptions.cs @@ -0,0 +1,100 @@ +using Microsoft.Extensions.Configuration; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace CallRecordInsights.Models +{ + public class CallRecordsGraphOptions + { + public int LifetimeMinutes { get; set; } + + public string Resource { get; set; } + + public string ChangeType { get; set; } + + public Uri NotificationUrl { get; set; } + + public IEnumerable Tenants { get; init; } + + public string Endpoint { get; set; } + + public CallRecordsGraphOptions() {} + + public CallRecordsGraphOptions(IConfigurationSection configurationSection) + { + LifetimeMinutes = configurationSection.GetValue(nameof(LifetimeMinutes), 4230); + Resource = configurationSection.GetValue(nameof(Resource), "communications/callRecords"); + ChangeType = configurationSection.GetValue(nameof(ChangeType), "created,updated"); + NotificationUrl = GetNotificationUrl(configurationSection); + Tenants = configurationSection.GetValue(nameof(Tenants))? + .Split(';', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries) + ?? Enumerable.Empty(); + Endpoint = configurationSection.GetValue(nameof(Endpoint), GLOBAL_ENDPOINT)?.ToLowerInvariant(); + if (!ValidEndpoints.Contains(Endpoint)) + throw new ArgumentException($"Invalid Endpoint {Endpoint}", nameof(configurationSection)); + } + + /// + /// Gets the notification URL from the configuration section for the . + /// + /// + /// + /// + private static Uri GetNotificationUrl(IConfigurationSection configurationSection) + { + var configuredUrl = configurationSection.GetValue(nameof(NotificationUrl)); + if (!Uri.TryCreate(configuredUrl, UriKind.Absolute, out var notificationUri)) + throw new ArgumentException($"Invalid NotificationUrl '{configuredUrl}'", nameof(configurationSection)); + + var query = notificationUri.GetComponents(UriComponents.Query, UriFormat.SafeUnescaped); + if (!string.IsNullOrEmpty(query)) + { + var queryParams = query + .Split( + '&', + StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries) + .ToDictionary( + q => q.Split('=', 2)[0], + q => q.Contains('=') ? Uri.UnescapeDataString(q.Split('=', 2)[1]) : null, + StringComparer.OrdinalIgnoreCase); + if (queryParams != null && queryParams.Remove("tenantId")) + { + var queryBuilder = new StringBuilder(); + var first = true; + foreach (var queryParam in queryParams) + { + if (!first) + queryBuilder.Append('&'); + else + first = false; + + queryBuilder.Append(queryParam.Key); + + if (queryParam.Value != null) + { + queryBuilder.Append('=') + .Append(Uri.EscapeDataString(queryParam.Value)); + } + } + // update the uri with the new query + var builder = new UriBuilder(notificationUri) + { + Query = queryBuilder.ToString() + }; + notificationUri = builder.Uri; + } + } + + return notificationUri; + } + + private const string GLOBAL_ENDPOINT = "graph.microsoft.com"; + private const string USGOV_ENDPOINT = "graph.microsoft.us"; + private const string USGOV_DOD_ENDPOINT = "dod-graph.microsoft.us"; + private const string CHINA_ENDPOINT = "microsoftgraph.chinacloudapi.cn"; + + private static readonly string[] ValidEndpoints = new[] { GLOBAL_ENDPOINT, USGOV_ENDPOINT, USGOV_DOD_ENDPOINT, CHINA_ENDPOINT }; + } +} diff --git a/src/Functions/Models/CosmosCallRecord.cs b/src/Functions/Models/CosmosCallRecord.cs new file mode 100644 index 0000000..4de0e9c --- /dev/null +++ b/src/Functions/Models/CosmosCallRecord.cs @@ -0,0 +1,288 @@ +using System; + +namespace CallRecordInsights.Models +{ + public class CosmosCallRecord : KustoCallRecord + { + private const string ROW_KEY_SEPARATOR = "_"; + +#pragma warning disable IDE1006 // Naming Styles -- id is a Cosmos DB reserved property + public string id { get => GetId(); set { } } +#pragma warning restore IDE1006 // Naming Styles + + /// + /// Gets the Cosmos id for the call record + /// The format is ____ + /// + /// + private string GetId() + { + return $"{CallId?.ToString().Replace(ROW_KEY_SEPARATOR, string.Empty)}" + + $"{ROW_KEY_SEPARATOR}" + + $"{SessionId?.ToString().Replace(ROW_KEY_SEPARATOR, string.Empty)}" + + $"{ROW_KEY_SEPARATOR}" + + $"{MediaLabel?.Replace(ROW_KEY_SEPARATOR, string.Empty)}" + + $"{ROW_KEY_SEPARATOR}" + + $"{StreamId?.Replace(ROW_KEY_SEPARATOR, string.Empty)}" + + $"{ROW_KEY_SEPARATOR}" + + $"{StreamDirection?.Replace(ROW_KEY_SEPARATOR, string.Empty)}"; + } + /// + /// Creates a new instance of from an instance of + /// + /// The to convert + /// + /// If is null + public static CosmosCallRecord Create(IKustoCallRecord callRecord) + { + var kustoCallRecord = callRecord as KustoCallRecord ?? throw new ArgumentNullException(nameof(callRecord)); + return new CosmosCallRecord + { + CallRecordTenantIdContext = kustoCallRecord.CallRecordTenantIdContext, + CallId = kustoCallRecord.CallId, + SessionId = kustoCallRecord.SessionId, + StreamId = kustoCallRecord.StreamId, + StreamDirection = kustoCallRecord.StreamDirection, + MediaLabel = kustoCallRecord.MediaLabel, + CallStartTime = kustoCallRecord.CallStartTime, + CallEndTime = kustoCallRecord.CallEndTime, + SessionStartTime = kustoCallRecord.SessionStartTime, + SessionEndTime = kustoCallRecord.SessionEndTime, + LastModifiedDateTimeOffset = kustoCallRecord.LastModifiedDateTimeOffset, + CallType = kustoCallRecord.CallType, + JoinWebUrl = kustoCallRecord.JoinWebUrl, + VideoCodec = kustoCallRecord.VideoCodec, + AudioCodec = kustoCallRecord.AudioCodec, + WasMediaBypassed = kustoCallRecord.WasMediaBypassed, + FailureStage = kustoCallRecord.FailureStage, + FailureReason = kustoCallRecord.FailureReason, + PacketUtilization = kustoCallRecord.PacketUtilization, + AverageBandwidthEstimate = kustoCallRecord.AverageBandwidthEstimate, + AverageJitter = kustoCallRecord.AverageJitter, + MaxJitter = kustoCallRecord.MaxJitter, + AverageRoundTripTime = kustoCallRecord.AverageRoundTripTime, + MaxRoundTripTime = kustoCallRecord.MaxRoundTripTime, + AverageAudioNetworkJitter = kustoCallRecord.AverageAudioNetworkJitter, + MaxAudioNetworkJitter = kustoCallRecord.MaxAudioNetworkJitter, + AverageAudioDegradation = kustoCallRecord.AverageAudioDegradation, + AveragePacketLossRate = kustoCallRecord.AveragePacketLossRate, + MaxPacketLossRate = kustoCallRecord.MaxPacketLossRate, + PostForwardErrorCorrectionPacketLossRate = kustoCallRecord.PostForwardErrorCorrectionPacketLossRate, + AverageRatioOfConcealedSamples = kustoCallRecord.AverageRatioOfConcealedSamples, + MaxRatioOfConcealedSamples = kustoCallRecord.MaxRatioOfConcealedSamples, + LowVideoProcessingCapabilityRatio = kustoCallRecord.LowVideoProcessingCapabilityRatio, + AverageVideoFrameRate = kustoCallRecord.AverageVideoFrameRate, + AverageReceivedFrameRate = kustoCallRecord.AverageReceivedFrameRate, + LowFrameRateRatio = kustoCallRecord.LowFrameRateRatio, + AverageVideoPacketLossRate = kustoCallRecord.AverageVideoPacketLossRate, + AverageVideoFrameLossPercentage = kustoCallRecord.AverageVideoFrameLossPercentage, + Organizer_UserDisplayName = kustoCallRecord.Organizer_UserDisplayName, + Organizer_UserId = kustoCallRecord.Organizer_UserId, + Organizer_UserTenantId = kustoCallRecord.Organizer_UserTenantId, + Organizer_ApplicationInstanceDisplayName = kustoCallRecord.Organizer_ApplicationInstanceDisplayName, + Organizer_ApplicationInstanceId = kustoCallRecord.Organizer_ApplicationInstanceId, + Organizer_ApplicationInstanceTenantId = kustoCallRecord.Organizer_ApplicationInstanceTenantId, + Organizer_GuestDisplayName = kustoCallRecord.Organizer_GuestDisplayName, + Organizer_GuestId = kustoCallRecord.Organizer_GuestId, + Organizer_GuestTenantId = kustoCallRecord.Organizer_GuestTenantId, + Organizer_PhoneDisplayName = kustoCallRecord.Organizer_PhoneDisplayName, + Organizer_PhoneId = kustoCallRecord.Organizer_PhoneId, + Organizer_PhoneTenantId = kustoCallRecord.Organizer_PhoneTenantId, + Organizer_OnPremisesDisplayName = kustoCallRecord.Organizer_OnPremisesDisplayName, + Organizer_OnPremisesId = kustoCallRecord.Organizer_OnPremisesId, + Organizer_OnPremisesTenantId = kustoCallRecord.Organizer_OnPremisesTenantId, + Organizer_EncryptedDisplayName = kustoCallRecord.Organizer_EncryptedDisplayName, + Organizer_EncryptedId = kustoCallRecord.Organizer_EncryptedId, + Organizer_EncryptedTenantId = kustoCallRecord.Organizer_EncryptedTenantId, + Organizer_AcsUserDisplayName = kustoCallRecord.Organizer_AcsUserDisplayName, + Organizer_AcsUserId = kustoCallRecord.Organizer_AcsUserId, + Organizer_AcsUserTenantId = kustoCallRecord.Organizer_AcsUserTenantId, + Organizer_SpoolUserDisplayName = kustoCallRecord.Organizer_SpoolUserDisplayName, + Organizer_SpoolUserId = kustoCallRecord.Organizer_SpoolUserId, + Organizer_SpoolUserTenantId = kustoCallRecord.Organizer_SpoolUserTenantId, + Organizer_AcsApplicationInstanceDisplayName = kustoCallRecord.Organizer_AcsApplicationInstanceDisplayName, + Organizer_AcsApplicationInstanceId = kustoCallRecord.Organizer_AcsApplicationInstanceId, + Organizer_AcsApplicationInstanceTenantId = kustoCallRecord.Organizer_AcsApplicationInstanceTenantId, + Organizer_SpoolApplicationInstanceDisplayName = kustoCallRecord.Organizer_SpoolApplicationInstanceDisplayName, + Organizer_SpoolApplicationInstanceId = kustoCallRecord.Organizer_SpoolApplicationInstanceId, + Organizer_SpoolApplicationInstanceTenantId = kustoCallRecord.Organizer_SpoolApplicationInstanceTenantId, + Callee_UserDisplayName = kustoCallRecord.Callee_UserDisplayName, + Callee_UserId = kustoCallRecord.Callee_UserId, + Callee_UserTenantId = kustoCallRecord.Callee_UserTenantId, + Callee_ApplicationInstanceDisplayName = kustoCallRecord.Callee_ApplicationInstanceDisplayName, + Callee_ApplicationInstanceId = kustoCallRecord.Callee_ApplicationInstanceId, + Callee_ApplicationInstanceTenantId = kustoCallRecord.Callee_ApplicationInstanceTenantId, + Callee_GuestDisplayName = kustoCallRecord.Callee_GuestDisplayName, + Callee_GuestId = kustoCallRecord.Callee_GuestId, + Callee_GuestTenantId = kustoCallRecord.Callee_GuestTenantId, + Callee_PhoneDisplayName = kustoCallRecord.Callee_PhoneDisplayName, + Callee_PhoneId = kustoCallRecord.Callee_PhoneId, + Callee_PhoneTenantId = kustoCallRecord.Callee_PhoneTenantId, + Callee_OnPremisesDisplayName = kustoCallRecord.Callee_OnPremisesDisplayName, + Callee_OnPremisesId = kustoCallRecord.Callee_OnPremisesId, + Callee_OnPremisesTenantId = kustoCallRecord.Callee_OnPremisesTenantId, + Callee_EncryptedDisplayName = kustoCallRecord.Callee_EncryptedDisplayName, + Callee_EncryptedId = kustoCallRecord.Callee_EncryptedId, + Callee_EncryptedTenantId = kustoCallRecord.Callee_EncryptedTenantId, + Callee_AcsUserDisplayName = kustoCallRecord.Callee_AcsUserDisplayName, + Callee_AcsUserId = kustoCallRecord.Callee_AcsUserId, + Callee_AcsUserTenantId = kustoCallRecord.Callee_AcsUserTenantId, + Callee_SpoolUserDisplayName = kustoCallRecord.Callee_SpoolUserDisplayName, + Callee_SpoolUserId = kustoCallRecord.Callee_SpoolUserId, + Callee_SpoolUserTenantId = kustoCallRecord.Callee_SpoolUserTenantId, + Callee_AcsApplicationInstanceDisplayName = kustoCallRecord.Callee_AcsApplicationInstanceDisplayName, + Callee_AcsApplicationInstanceId = kustoCallRecord.Callee_AcsApplicationInstanceId, + Callee_AcsApplicationInstanceTenantId = kustoCallRecord.Callee_AcsApplicationInstanceTenantId, + Callee_SpoolApplicationInstanceDisplayName = kustoCallRecord.Callee_SpoolApplicationInstanceDisplayName, + Callee_SpoolApplicationInstanceId = kustoCallRecord.Callee_SpoolApplicationInstanceId, + Callee_SpoolApplicationInstanceTenantId = kustoCallRecord.Callee_SpoolApplicationInstanceTenantId, + Callee_EndpointType = kustoCallRecord.Callee_EndpointType, + Callee_ProductFamily = kustoCallRecord.Callee_ProductFamily, + Callee_Platform = kustoCallRecord.Callee_Platform, + Callee_UserAgentHeaderValue = kustoCallRecord.Callee_UserAgentHeaderValue, + Callee_ServiceRole = kustoCallRecord.Callee_ServiceRole, + Callee_ApplicationVersion = kustoCallRecord.Callee_ApplicationVersion, + Callee_AzureAdAppId = kustoCallRecord.Callee_AzureAdAppId, + Callee_CommunicationServiceId = kustoCallRecord.Callee_CommunicationServiceId, + Callee_ConnectionType = kustoCallRecord.Callee_ConnectionType, + Callee_ReflexiveIPAddress = kustoCallRecord.Callee_ReflexiveIPAddress, + Callee_Subnet = kustoCallRecord.Callee_Subnet, + Callee_IpAddress = kustoCallRecord.Callee_IpAddress, + Callee_MacAddress = kustoCallRecord.Callee_MacAddress, + Callee_LinkSpeed = kustoCallRecord.Callee_LinkSpeed, + Callee_NetworkTransportProtocol = kustoCallRecord.Callee_NetworkTransportProtocol, + Callee_Port = kustoCallRecord.Callee_Port, + Callee_RelayIPAddress = kustoCallRecord.Callee_RelayIPAddress, + Callee_RelayPort = kustoCallRecord.Callee_RelayPort, + Callee_DnsSuffix = kustoCallRecord.Callee_DnsSuffix, + Callee_TraceRouteHops = kustoCallRecord.Callee_TraceRouteHops, + Callee_BSSID = kustoCallRecord.Callee_BSSID, + Callee_WifiRadioType = kustoCallRecord.Callee_WifiRadioType, + Callee_WifiBand = kustoCallRecord.Callee_WifiBand, + Callee_WifiChannel = kustoCallRecord.Callee_WifiChannel, + Callee_WifiSignalStrength = kustoCallRecord.Callee_WifiSignalStrength, + Callee_WifiBatteryCharge = kustoCallRecord.Callee_WifiBatteryCharge, + Callee_WifiMicrosoftDriver = kustoCallRecord.Callee_WifiMicrosoftDriver, + Callee_WifiMicrosoftDriverVersion = kustoCallRecord.Callee_WifiMicrosoftDriverVersion, + Callee_WifiVendorDriver = kustoCallRecord.Callee_WifiVendorDriver, + Callee_WifiVendorDriverVersion = kustoCallRecord.Callee_WifiVendorDriverVersion, + Callee_CaptureDeviceName = kustoCallRecord.Callee_CaptureDeviceName, + Callee_CaptureDeviceDriver = kustoCallRecord.Callee_CaptureDeviceDriver, + Callee_RenderDeviceName = kustoCallRecord.Callee_RenderDeviceName, + Callee_RenderDeviceDriver = kustoCallRecord.Callee_RenderDeviceDriver, + Callee_SentSignalLevel = kustoCallRecord.Callee_SentSignalLevel, + Callee_SentNoiseLevel = kustoCallRecord.Callee_SentNoiseLevel, + Callee_MicGlitchRate = kustoCallRecord.Callee_MicGlitchRate, + Callee_ReceivedSignalLevel = kustoCallRecord.Callee_ReceivedSignalLevel, + Callee_ReceivedNoiseLevel = kustoCallRecord.Callee_ReceivedNoiseLevel, + Callee_SpeakerGlitchRate = kustoCallRecord.Callee_SpeakerGlitchRate, + Callee_HowlingEventCount = kustoCallRecord.Callee_HowlingEventCount, + Callee_InitialSignalLevelRootMeanSquare = kustoCallRecord.Callee_InitialSignalLevelRootMeanSquare, + Callee_DeviceGlitchEventRatio = kustoCallRecord.Callee_DeviceGlitchEventRatio, + Callee_DeviceClippingEventRatio = kustoCallRecord.Callee_DeviceClippingEventRatio, + Callee_LowSpeechToNoiseEventRatio = kustoCallRecord.Callee_LowSpeechToNoiseEventRatio, + Callee_CaptureNotFunctioningEventRatio = kustoCallRecord.Callee_CaptureNotFunctioningEventRatio, + Callee_SentQualityEventRatio = kustoCallRecord.Callee_SentQualityEventRatio, + Callee_LowSpeechLevelEventRatio = kustoCallRecord.Callee_LowSpeechLevelEventRatio, + Callee_RenderNotFunctioningEventRatio = kustoCallRecord.Callee_RenderNotFunctioningEventRatio, + Callee_ReceivedQualityEventRatio = kustoCallRecord.Callee_ReceivedQualityEventRatio, + Callee_RenderZeroVolumeEventRatio = kustoCallRecord.Callee_RenderZeroVolumeEventRatio, + Callee_RenderMuteEventRatio = kustoCallRecord.Callee_RenderMuteEventRatio, + Callee_CpuInsufficentEventRatio = kustoCallRecord.Callee_CpuInsufficentEventRatio, + Callee_DelayEventRatio = kustoCallRecord.Callee_DelayEventRatio, + Callee_BandwidthLowEventRatio = kustoCallRecord.Callee_BandwidthLowEventRatio, + Callee_FeedbackRating = kustoCallRecord.Callee_FeedbackRating, + Callee_FeedbackText = kustoCallRecord.Callee_FeedbackText, + Callee_FeedbackTokens = kustoCallRecord.Callee_FeedbackTokens, + Caller_UserDisplayName = kustoCallRecord.Caller_UserDisplayName, + Caller_UserId = kustoCallRecord.Caller_UserId, + Caller_UserTenantId = kustoCallRecord.Caller_UserTenantId, + Caller_ApplicationInstanceDisplayName = kustoCallRecord.Caller_ApplicationInstanceDisplayName, + Caller_ApplicationInstanceId = kustoCallRecord.Caller_ApplicationInstanceId, + Caller_ApplicationInstanceTenantId = kustoCallRecord.Caller_ApplicationInstanceTenantId, + Caller_GuestDisplayName = kustoCallRecord.Caller_GuestDisplayName, + Caller_GuestId = kustoCallRecord.Caller_GuestId, + Caller_GuestTenantId = kustoCallRecord.Caller_GuestTenantId, + Caller_PhoneDisplayName = kustoCallRecord.Caller_PhoneDisplayName, + Caller_PhoneId = kustoCallRecord.Caller_PhoneId, + Caller_PhoneTenantId = kustoCallRecord.Caller_PhoneTenantId, + Caller_OnPremisesDisplayName = kustoCallRecord.Caller_OnPremisesDisplayName, + Caller_OnPremisesId = kustoCallRecord.Caller_OnPremisesId, + Caller_OnPremisesTenantId = kustoCallRecord.Caller_OnPremisesTenantId, + Caller_EncryptedDisplayName = kustoCallRecord.Caller_EncryptedDisplayName, + Caller_EncryptedId = kustoCallRecord.Caller_EncryptedId, + Caller_EncryptedTenantId = kustoCallRecord.Caller_EncryptedTenantId, + Caller_AcsUserDisplayName = kustoCallRecord.Caller_AcsUserDisplayName, + Caller_AcsUserId = kustoCallRecord.Caller_AcsUserId, + Caller_AcsUserTenantId = kustoCallRecord.Caller_AcsUserTenantId, + Caller_SpoolUserDisplayName = kustoCallRecord.Caller_SpoolUserDisplayName, + Caller_SpoolUserId = kustoCallRecord.Caller_SpoolUserId, + Caller_SpoolUserTenantId = kustoCallRecord.Caller_SpoolUserTenantId, + Caller_AcsApplicationInstanceDisplayName = kustoCallRecord.Caller_AcsApplicationInstanceDisplayName, + Caller_AcsApplicationInstanceId = kustoCallRecord.Caller_AcsApplicationInstanceId, + Caller_AcsApplicationInstanceTenantId = kustoCallRecord.Caller_AcsApplicationInstanceTenantId, + Caller_SpoolApplicationInstanceDisplayName = kustoCallRecord.Caller_SpoolApplicationInstanceDisplayName, + Caller_SpoolApplicationInstanceId = kustoCallRecord.Caller_SpoolApplicationInstanceId, + Caller_SpoolApplicationInstanceTenantId = kustoCallRecord.Caller_SpoolApplicationInstanceTenantId, + Caller_EndpointType = kustoCallRecord.Caller_EndpointType, + Caller_ProductFamily = kustoCallRecord.Caller_ProductFamily, + Caller_Platform = kustoCallRecord.Caller_Platform, + Caller_UserAgentHeaderValue = kustoCallRecord.Caller_UserAgentHeaderValue, + Caller_ServiceRole = kustoCallRecord.Caller_ServiceRole, + Caller_ApplicationVersion = kustoCallRecord.Caller_ApplicationVersion, + Caller_AzureAdAppId = kustoCallRecord.Caller_AzureAdAppId, + Caller_CommunicationServiceId = kustoCallRecord.Caller_CommunicationServiceId, + Caller_ConnectionType = kustoCallRecord.Caller_ConnectionType, + Caller_ReflexiveIPAddress = kustoCallRecord.Caller_ReflexiveIPAddress, + Caller_Subnet = kustoCallRecord.Caller_Subnet, + Caller_IpAddress = kustoCallRecord.Caller_IpAddress, + Caller_MacAddress = kustoCallRecord.Caller_MacAddress, + Caller_LinkSpeed = kustoCallRecord.Caller_LinkSpeed, + Caller_NetworkTransportProtocol = kustoCallRecord.Caller_NetworkTransportProtocol, + Caller_Port = kustoCallRecord.Caller_Port, + Caller_RelayIPAddress = kustoCallRecord.Caller_RelayIPAddress, + Caller_RelayPort = kustoCallRecord.Caller_RelayPort, + Caller_DnsSuffix = kustoCallRecord.Caller_DnsSuffix, + Caller_TraceRouteHops = kustoCallRecord.Caller_TraceRouteHops, + Caller_BSSID = kustoCallRecord.Caller_BSSID, + Caller_WifiRadioType = kustoCallRecord.Caller_WifiRadioType, + Caller_WifiBand = kustoCallRecord.Caller_WifiBand, + Caller_WifiChannel = kustoCallRecord.Caller_WifiChannel, + Caller_WifiSignalStrength = kustoCallRecord.Caller_WifiSignalStrength, + Caller_WifiBatteryCharge = kustoCallRecord.Caller_WifiBatteryCharge, + Caller_WifiMicrosoftDriver = kustoCallRecord.Caller_WifiMicrosoftDriver, + Caller_WifiMicrosoftDriverVersion = kustoCallRecord.Caller_WifiMicrosoftDriverVersion, + Caller_WifiVendorDriver = kustoCallRecord.Caller_WifiVendorDriver, + Caller_WifiVendorDriverVersion = kustoCallRecord.Caller_WifiVendorDriverVersion, + Caller_CaptureDeviceName = kustoCallRecord.Caller_CaptureDeviceName, + Caller_CaptureDeviceDriver = kustoCallRecord.Caller_CaptureDeviceDriver, + Caller_RenderDeviceName = kustoCallRecord.Caller_RenderDeviceName, + Caller_RenderDeviceDriver = kustoCallRecord.Caller_RenderDeviceDriver, + Caller_SentSignalLevel = kustoCallRecord.Caller_SentSignalLevel, + Caller_SentNoiseLevel = kustoCallRecord.Caller_SentNoiseLevel, + Caller_MicGlitchRate = kustoCallRecord.Caller_MicGlitchRate, + Caller_ReceivedSignalLevel = kustoCallRecord.Caller_ReceivedSignalLevel, + Caller_ReceivedNoiseLevel = kustoCallRecord.Caller_ReceivedNoiseLevel, + Caller_SpeakerGlitchRate = kustoCallRecord.Caller_SpeakerGlitchRate, + Caller_HowlingEventCount = kustoCallRecord.Caller_HowlingEventCount, + Caller_InitialSignalLevelRootMeanSquare = kustoCallRecord.Caller_InitialSignalLevelRootMeanSquare, + Caller_DeviceGlitchEventRatio = kustoCallRecord.Caller_DeviceGlitchEventRatio, + Caller_DeviceClippingEventRatio = kustoCallRecord.Caller_DeviceClippingEventRatio, + Caller_LowSpeechToNoiseEventRatio = kustoCallRecord.Caller_LowSpeechToNoiseEventRatio, + Caller_CaptureNotFunctioningEventRatio = kustoCallRecord.Caller_CaptureNotFunctioningEventRatio, + Caller_SentQualityEventRatio = kustoCallRecord.Caller_SentQualityEventRatio, + Caller_LowSpeechLevelEventRatio = kustoCallRecord.Caller_LowSpeechLevelEventRatio, + Caller_RenderNotFunctioningEventRatio = kustoCallRecord.Caller_RenderNotFunctioningEventRatio, + Caller_ReceivedQualityEventRatio = kustoCallRecord.Caller_ReceivedQualityEventRatio, + Caller_RenderZeroVolumeEventRatio = kustoCallRecord.Caller_RenderZeroVolumeEventRatio, + Caller_RenderMuteEventRatio = kustoCallRecord.Caller_RenderMuteEventRatio, + Caller_CpuInsufficentEventRatio = kustoCallRecord.Caller_CpuInsufficentEventRatio, + Caller_DelayEventRatio = kustoCallRecord.Caller_DelayEventRatio, + Caller_BandwidthLowEventRatio = kustoCallRecord.Caller_BandwidthLowEventRatio, + Caller_FeedbackRating = kustoCallRecord.Caller_FeedbackRating, + Caller_FeedbackText = kustoCallRecord.Caller_FeedbackText, + Caller_FeedbackTokens = kustoCallRecord.Caller_FeedbackTokens, + }; + } + } +} diff --git a/src/Functions/Models/CosmosEventNotification.cs b/src/Functions/Models/CosmosEventNotification.cs new file mode 100644 index 0000000..2e6d740 --- /dev/null +++ b/src/Functions/Models/CosmosEventNotification.cs @@ -0,0 +1,34 @@ +using System.Text.Json.Serialization; + +namespace CallRecordInsights.Models +{ + public class CosmosEventNotification + { + public CosmosEventNotification(GraphEventNotification notification) + { + Id = notification.ResourceData.Id; + TenantId = notification.TenantId; + ODataType = notification.ResourceData.ODataType; + ODataId = notification.ResourceData.ODataId; + } + + public CosmosEventNotification() { } + + public string Id { get; set; } + + public string TenantId { get; set; } + + [JsonPropertyName("@odata.id")] + public string ODataId { get; set; } + + [JsonPropertyName("@odata.type")] + public string ODataType { get; set; } + + /// + /// Gets the queue string representation of the notification + /// This is in the format of | + /// + /// + public string GetQueueString() => $"{TenantId}|{Id}"; + } +} diff --git a/src/Functions/Models/EventNotificationResourceData.cs b/src/Functions/Models/EventNotificationResourceData.cs new file mode 100644 index 0000000..210ea2f --- /dev/null +++ b/src/Functions/Models/EventNotificationResourceData.cs @@ -0,0 +1,23 @@ +using System.Text.Json.Serialization; + +namespace CallRecordInsights.Models +{ + public class EventNotificationResourceData + { + private const string ODATA_TYPE = "#microsoft.graph.callrecord"; + [JsonPropertyName("@odata.type")] + public string ODataType { get; set; } + + [JsonPropertyName("@odata.id")] + public string ODataId { get; set; } + + [JsonPropertyName("id")] + public string Id { get; set; } + + /// + /// Determines if the event notification is a call record event + /// + /// + public bool IsCallRecordEvent() => ODATA_TYPE.Equals(ODataType, System.StringComparison.OrdinalIgnoreCase); + } +} \ No newline at end of file diff --git a/src/Functions/Models/GraphEventNotification.cs b/src/Functions/Models/GraphEventNotification.cs new file mode 100644 index 0000000..edae49a --- /dev/null +++ b/src/Functions/Models/GraphEventNotification.cs @@ -0,0 +1,31 @@ +using Microsoft.Graph.Models; +using System; +using System.Text.Json.Serialization; + +namespace CallRecordInsights.Models +{ + public class GraphEventNotification + { + [JsonPropertyName("subscriptionId")] + public string SubscriptionId { get; set; } + + [JsonPropertyName("clientState")] + public string ClientState { get; set; } + + [JsonPropertyName("changeType")] + [JsonConverter(typeof(JsonStringEnumConverter))] + public ChangeType ChangeType { get; set; } + + [JsonPropertyName("resource")] + public string Resource { get; set; } + + [JsonPropertyName("subscriptionExpirationDateTime")] + public DateTimeOffset SubscriptionExpirationDateTime { get; set; } + + [JsonPropertyName("resourceData")] + public EventNotificationResourceData ResourceData { get; set; } + + [JsonPropertyName("tenantId")] + public string TenantId { get; set; } + } +} \ No newline at end of file diff --git a/src/Functions/Models/GraphNotificationBatch.cs b/src/Functions/Models/GraphNotificationBatch.cs new file mode 100644 index 0000000..2193579 --- /dev/null +++ b/src/Functions/Models/GraphNotificationBatch.cs @@ -0,0 +1,11 @@ +using System.Collections.Generic; +using System.Text.Json.Serialization; + +namespace CallRecordInsights.Models +{ + public class GraphNotificationBatch + { + [JsonPropertyName("value")] + public IEnumerable Value { get; set; } + } +} \ No newline at end of file diff --git a/src/Functions/Services/AzureIdentityMultiTenantGraphAuthenticationProvider.cs b/src/Functions/Services/AzureIdentityMultiTenantGraphAuthenticationProvider.cs new file mode 100644 index 0000000..e8605dc --- /dev/null +++ b/src/Functions/Services/AzureIdentityMultiTenantGraphAuthenticationProvider.cs @@ -0,0 +1,103 @@ +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Azure.Core; +using Microsoft.Extensions.Logging; +using Microsoft.Identity.Web; +using Microsoft.Kiota.Abstractions; +using Microsoft.Kiota.Abstractions.Authentication; + +namespace CallRecordInsights.Services +{ + public class AzureIdentityMultiTenantGraphAuthenticationProvider : IAuthenticationProvider + { + private const string AUTHORIZATION_HEADER_KEY = "Authorization"; + private const string PROTOCOL_SCHEME = "Bearer"; + private const string DEFAULT_TENANT_LOOKUP = "DEFAULT"; + + private static readonly ConcurrentDictionary _tokenCache = new(); + + private readonly GraphServiceClientOptions _defaultAuthenticationOptions; + private readonly TokenCredential _credential; + private readonly ILogger logger; + private static readonly string[] AppOnlyScopes = new[] { "https://graph.microsoft.com/.default" }; + + public AzureIdentityMultiTenantGraphAuthenticationProvider( + TokenCredential credential, + ILogger logger, + GraphServiceClientOptions graphServiceClientOptions = null) + { + _credential = credential ?? throw new ArgumentNullException(nameof(credential)); + this.logger = logger; + if (graphServiceClientOptions?.RequestAppToken == false) + throw new InvalidOperationException($"The {nameof(AzureIdentityMultiTenantGraphAuthenticationProvider)} only supports app only authentication."); + _defaultAuthenticationOptions = graphServiceClientOptions ?? new GraphServiceClientOptions(); + _defaultAuthenticationOptions.RequestAppToken = true; + } + + /// + /// This method will authenticate the request using the provided in the constructor. + /// Override the default TenantId by setting the property on the parameter. + /// + /// + /// + /// + /// + /// + public async Task AuthenticateRequestAsync(RequestInformation request, Dictionary additionalAuthenticationContext = null, CancellationToken cancellationToken = default) + { + var graphServiceClientOptions = request.RequestOptions.OfType().FirstOrDefault() ?? _defaultAuthenticationOptions; + + if (!PROTOCOL_SCHEME.Equals(graphServiceClientOptions?.ProtocolScheme, StringComparison.OrdinalIgnoreCase)) + throw new InvalidOperationException($"The {nameof(AzureIdentityMultiTenantGraphAuthenticationProvider)} only supports the {PROTOCOL_SCHEME} protocol scheme."); + if (graphServiceClientOptions?.RequestAppToken == false) + throw new InvalidOperationException($"The {nameof(AzureIdentityMultiTenantGraphAuthenticationProvider)} only supports app only authentication."); + + request.Headers.Remove(AUTHORIZATION_HEADER_KEY); + + var result = await GetTokenAsync( + graphServiceClientOptions.AcquireTokenOptions?.Tenant, + cancellationToken) + .ConfigureAwait(false); + + request.Headers.Add(AUTHORIZATION_HEADER_KEY, GetBearerToken(result)); + } + + /// + /// Gets a token for the specified tenant. If no tenant is specified, the default tenant will be used. + /// + /// + /// + /// + private async ValueTask GetTokenAsync(string tenant, CancellationToken cancellationToken = default) + { + if (string.IsNullOrEmpty(tenant)) + tenant = DEFAULT_TENANT_LOOKUP; + + if (_tokenCache.TryGetValue(tenant, out var accessToken) && accessToken.ExpiresOn > DateTimeOffset.UtcNow.AddMinutes(5)) + { + logger?.LogInformation("Using cached token for tenant '{Tenant}'", tenant); + return accessToken; + } + + logger?.LogInformation("Getting new token for tenant '{Tenant}'", tenant); + var newToken = await _credential.GetTokenAsync( + new TokenRequestContext(AppOnlyScopes, tenantId:tenant), + cancellationToken) + .ConfigureAwait(false); + + _tokenCache[tenant] = newToken; + return newToken; + } + + /// + /// Gets the Bearer token from the . + /// + /// + /// + private static string GetBearerToken(AccessToken accessToken) => string.Join(' ', PROTOCOL_SCHEME, accessToken.Token); + } +} diff --git a/src/Functions/Services/CallRecordsDataContext.cs b/src/Functions/Services/CallRecordsDataContext.cs new file mode 100644 index 0000000..5da1e21 --- /dev/null +++ b/src/Functions/Services/CallRecordsDataContext.cs @@ -0,0 +1,467 @@ +using Azure.Core; +using CallRecordInsights.Models; +using Microsoft.Azure.Cosmos; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Logging; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Threading; +using System.Threading.Tasks; + +namespace CallRecordInsights.Services +{ + public class CallRecordsDataContext : ICallRecordsDataContext + { + public enum Operation + { + Create, + Upsert, + Skip, + Delete + } + + private const int MAX_TRANSACTION_BATCH_SIZE = 100; + + private const string DEFAULT_DATABASE_ID = "callrecordinsights"; + private const string DEFAULT_PROCESSED_CONTAINER_ID = "records"; + + private readonly static string[] PROCESSED_CONTAINER_PARTITION_KEY_PATHS = new[] { $"/{nameof(CosmosCallRecord.CallRecordTenantIdContext)}", $"/{nameof(CosmosCallRecord.CallId)}" }; + + private readonly ILogger logger; + private readonly Database callRecordsDatabase; + private readonly string processedContainerId; + private Container processedContainer; + + public CallRecordsDataContext( + TokenCredential tokenCredential, + IConfiguration configuration, + ILogger logger) + { + this.logger = logger; + var endpointUri = configuration.GetValue("EndpointUri"); + + if (string.IsNullOrEmpty(endpointUri)) + throw new ArgumentException("EndpointUri must be configured", nameof(configuration)); + + + var callRecordsDatabaseId = configuration.GetValue("Database", DEFAULT_DATABASE_ID); + processedContainerId = configuration.GetValue("ProcessedContainer", DEFAULT_PROCESSED_CONTAINER_ID); + + var cosmosClient = new CosmosClient(endpointUri, tokenCredential); + + callRecordsDatabase = cosmosClient.GetDatabase(callRecordsDatabaseId); + Endpoint = $"{endpointUri.TrimEnd('/')}/dbs/{callRecordsDatabase.Id}/colls/{processedContainerId}"; + } + + public string Endpoint { get; private set; } + + /// + /// Tests if the CosmosDB Processed Container is accessible + /// + /// + /// + public async Task IsAccessible(CancellationToken cancellationToken = default) + { + try + { + var processedContainer = await GetProcessedContainerAsync(cancellationToken) + .ConfigureAwait(false); + + using var queryResult = processedContainer.GetItemQueryIterator(new QueryDefinition("SELECT TOP 1 * FROM c")); + + if (queryResult.HasMoreResults) + _ = await queryResult.ReadNextAsync(cancellationToken); + + return true; + } + catch (Exception ex) when (ex is CosmosException or InvalidOperationException or TaskCanceledException or OperationCanceledException) + { + logger?.LogError(ex, "CosmosDB is not accessible"); + return false; + } + } + + private class ProcessedOperationQueryResult + { + public int Count { get; set; } + public DateTimeOffset? LastModifiedDateTimeOffset { get; set; } + } + + /// + /// Determines what operation should be performed for the s generated for a given callId and tenantIdContext against the Processed Container + /// If no record exists, the operation is + /// If the record(s) exist but are older or have a different row count, the operation is + /// If the record(s) exist and are not older and have the same row count, the operation is + /// + /// The + /// The + /// The + /// The number of s generated for the + /// + /// The required + public async Task GetNeededProcessedRecordsOperationAsync( + string tenantIdContext, + Guid callId, + DateTimeOffset? lastModified, + int count, + CancellationToken cancellationToken = default) + { + logger?.LogInformation( + "Checking if {CallId} of {TenantId} with {LastModified} exists or is older", + callId, + tenantIdContext, + lastModified); + + var processedContainer = await GetProcessedContainerAsync(cancellationToken) + .ConfigureAwait(false); + + using var queryResult = processedContainer.GetItemQueryIterator( + queryDefinition: new QueryDefinition("SELECT COUNT(1) AS Count, MAX(c.LastModifiedDateTimeOffset) AS LastModifiedDateTimeOffset FROM c WHERE c.CallRecordTenantIdContext = @tenantIdContext AND c.CallId = @callId") + .WithParameter("@tenantIdContext", tenantIdContext) + .WithParameter("@callId",callId), + requestOptions: new QueryRequestOptions { PartitionKey = new PartitionKeyBuilder().Add(tenantIdContext).Add(callId.ToString()).Build() }); + + var cost = 0.0; + if (queryResult.HasMoreResults) + { + var resultsPage = await queryResult.ReadNextAsync(cancellationToken); + cost = resultsPage.RequestCharge; + if (resultsPage.Any()) + { + var existingLastModified = resultsPage.First().LastModifiedDateTimeOffset; + var existingCount = resultsPage.First().Count; + if (existingCount == count && existingLastModified >= lastModified) + { + logger?.LogInformation( + "Should Create {CallId} of {TenantId} last modified {LastModified} with {Count} rows, as existing record is not older {ExistingLastModified} and has the same row count {ExistingCount}, RU: {RU_Cost}", + callId, + tenantIdContext, + lastModified, + count, + existingLastModified, + existingCount, + cost); + + return Operation.Skip; + } + if (existingCount > 0) + { + logger?.LogInformation( + "Should Update {CallId} of {TenantId} last modified {LastModified} with {Count} rows, as existing record is older {ExistingLastModified} or has a different row count {ExistingCount}, RU: {RU_Cost}", + callId, + tenantIdContext, + lastModified, + count, + existingLastModified, + existingCount, + cost); + + return Operation.Upsert; + } + } + } + + logger?.LogInformation( + "Should Create {CallId} of {TenantId} as no record exists, RU: {RU_Cost}", + callId, + tenantIdContext, + cost); + + return Operation.Create; + } + + /// + /// Creates or upserts the s generated for a given callId and tenantIdContext in the Processed Container + /// It is performed in batches of , and if any batch fails, a rollback is attempted + /// + /// The of records to create or upsert. + /// Must all be from the same and + /// + /// The + /// The + /// to perform, must be or + /// + /// + /// If any operation fails and the subsequent rollback fails, the from the failed operation is thrown + /// If is not or + public async Task CreateOrUpsertProcessedRecordsAsync( + IReadOnlyList cosmosCallRecords, + string tenantIdContext, + Guid callIdGuid, + Operation operation, + CancellationToken cancellationToken = default) + { + var callId = callIdGuid.ToString(); + + if (operation != Operation.Create && operation != Operation.Upsert) + throw new ArgumentException($"Operation must be {nameof(Operation.Create)} or {nameof(Operation.Upsert)}", nameof(operation)); + + var partitionKey = new PartitionKeyBuilder() + .Add(tenantIdContext) + .Add(callId) + .Build(); + + var (processed, exception) = await ProcessBatchOperationsAsync( + operation, + partitionKey, + callId, + cosmosCallRecords, + cosmosCallRecords.Count, + cancellationToken) + .ConfigureAwait(false); + + if (exception != null) + { + var (_, deleteException) = await ProcessBatchOperationsAsync( + Operation.Delete, + partitionKey, + callId, + cosmosCallRecords, + processed, + cancellationToken) + .ConfigureAwait(false); + + if (deleteException != null) + { + var aggregateException = new AggregateException(exception, deleteException); + logger?.LogError( + aggregateException, + "Error processing {Operation} for {CallId} of {Count} rows with {Count} processed and error rolling back. PartitionKey {PartitionKey}", + operation, + callId, + cosmosCallRecords.Count, + processed, + partitionKey.ToString()); + throw aggregateException; + } + + logger?.LogError( + exception, + "Error processing {Operation} for {CallId} of {Count} rows with {Count} processed, successfully rolled-back. PartitionKey {PartitionKey}", + operation, + callId, + cosmosCallRecords.Count, + processed, + partitionKey.ToString()); + + throw exception; + } + } + + /// + /// Processes CosmosCallRecords in batches of for the given + /// If any batch fails, the remaining items are skipped and the exception is returned + /// + /// The to perform + /// The for the operation + /// The of the records + /// The full to process + /// The limit of records to process + /// + /// A with the number of successfully processed records + /// and the , if any, thrown by the batch + private async Task<(int processed, Exception exception)> ProcessBatchOperationsAsync( + Operation operation, + PartitionKey partitionKey, + string callId, + IReadOnlyList cosmosCallRecords, + int numberToProcess, + CancellationToken cancellationToken = default) + { + var processed = 0; + Exception exception = default; + Container container = default; + + try + { + container = await GetProcessedContainerAsync(cancellationToken) + .ConfigureAwait(false); + + logger?.LogInformation( + "{Operation} for {CallId} of {Count} rows in {Container} in {Database}. PartitionKey {PartitionKey}", + operation, + callId, + cosmosCallRecords.Count, + container.Id, + container.Database.Id, + partitionKey.ToString()); + + for (var i = 0; i <= numberToProcess; i += MAX_TRANSACTION_BATCH_SIZE) + { + var batch = cosmosCallRecords + .Skip(i) + .Take(MAX_TRANSACTION_BATCH_SIZE); + + var currentBatchSize = batch.Count(); + + logger?.LogInformation( + "{Operation} batch for {CallId} of {Count} rows of {Total} in {Container} in {Database}. PartitionKey {PartitionKey}", + operation, + callId, + currentBatchSize, + numberToProcess, + container.Id, + container.Database.Id, + partitionKey.ToString()); + + var transaction = container.CreateTransactionalBatch(partitionKey); + + foreach (var cosmosCallRecord in batch) + { + switch (operation) + { + case Operation.Create: + transaction.CreateItem(cosmosCallRecord); + break; + case Operation.Upsert: + transaction.UpsertItem(cosmosCallRecord); + break; + case Operation.Delete: + transaction.DeleteItem(cosmosCallRecord.id); + break; + } + } + + var batchResponse = await transaction.ExecuteAsync(cancellationToken) + .ConfigureAwait(false); + + var cost = batchResponse.RequestCharge; + + if (!batchResponse.IsSuccessStatusCode) + { + logger?.LogError( + "{Operation} failure for {CallId} after {Count} rows of {Total} in {Container} in {Database}: {Status} {ErrorMessage} (retry:{RetryAfter}). PartitionKey {PartitionKey}, RU: {RU_Cost}", + operation, + callId, + processed, + numberToProcess, + container.Id, + container.Database.Id, + batchResponse.StatusCode, + batchResponse.ErrorMessage, + batchResponse.RetryAfter, + partitionKey.ToString(), + cost); + + logger?.LogError("Detail: {Diagnostic}", batchResponse.Diagnostics.ToString()); + + var substatus = 0; + for (var j = 0; j < batchResponse.Count(); j++) + { + var itemResponse = batchResponse[j]; + if (itemResponse.StatusCode == HttpStatusCode.FailedDependency) + continue; + + substatus = (int)itemResponse.StatusCode; + logger?.LogError( + "{Operation} failure for {CallId} after {Count} rows of {Total} in {Container} in {Database}: . PartitionKey {PartitionKey}", + operation, + callId, + processed + j, + numberToProcess, + container.Id, + container.Database.Id, + itemResponse.StatusCode, + itemResponse.RetryAfter, + partitionKey.ToString()); + } + + exception = new CosmosException(batchResponse.ErrorMessage, batchResponse.StatusCode, substatus, batchResponse.ActivityId, batchResponse.RequestCharge); + + return (processed, exception); + } + + processed += currentBatchSize; + + logger?.LogInformation( + "{Operation} success for {CallId} for {Count} rows of {Total} in {Container} in {Database}. PartitionKey {PartitionKey}, RU: {RU_Cost}", + operation, + callId, + processed, + numberToProcess, + container.Id, + container.Database.Id, + partitionKey.ToString(), + cost); + } + } + catch (Exception ex) when (ex is CosmosException or InvalidOperationException or TaskCanceledException or OperationCanceledException) + { + logger?.LogError( + ex, + "{Operation} failure for {CallId} after {Count} rows of {Total} in {Container} in {Database}. PartitionKey {PartitionKey}", + operation, + callId, + processed, + numberToProcess, + container?.Id, + container?.Database.Id, + partitionKey.ToString()); + exception = ex; + } + return (processed, exception); + } + + /// + /// Gets or creates the Processed Container in the CallRecords Database + /// + /// + /// + private async ValueTask GetProcessedContainerAsync(CancellationToken cancellationToken = default) + { + if (processedContainer is not null) + return processedContainer; + + if (string.IsNullOrEmpty(processedContainerId)) + return null; + + try + { + logger?.LogInformation( + "Getting or creating {Container} in {Database}", + processedContainerId, + callRecordsDatabase.Id); + + var indexingPolicy = new IndexingPolicy + { + IndexingMode = IndexingMode.Consistent, + }; + indexingPolicy.IncludedPaths.Add(new IncludedPath { Path = @"/CallRecordTenantIdContext/?" }); + indexingPolicy.IncludedPaths.Add(new IncludedPath { Path = @"/CallId/?" }); + indexingPolicy.IncludedPaths.Add(new IncludedPath { Path = @"/LastModifiedDateTimeOffset/?" }); + indexingPolicy.ExcludedPaths.Add(new ExcludedPath { Path = @"/*" }); + + var containerDefinition = new ContainerProperties + { + Id = processedContainerId, + PartitionKeyPaths = PROCESSED_CONTAINER_PARTITION_KEY_PATHS, + IndexingPolicy = indexingPolicy, + }; + + var throughputProperties = ThroughputProperties.CreateAutoscaleThroughput(1000); + + processedContainer = await callRecordsDatabase + .CreateContainerIfNotExistsAsync(containerDefinition, throughputProperties, cancellationToken: cancellationToken) + .ConfigureAwait(false); + + logger?.LogInformation( + "{Container} in {Database} is created", + processedContainer.Id, + callRecordsDatabase.Id); + } + catch (Exception ex) when (ex is CosmosException or InvalidOperationException or TaskCanceledException or OperationCanceledException) + { + logger?.LogError( + ex, + "Error getting or creating {Container} in {Database}", + processedContainerId, + callRecordsDatabase.Id); + + throw; + } + return processedContainer; + } + } +} diff --git a/src/Functions/Services/CallRecordsGraphContext.cs b/src/Functions/Services/CallRecordsGraphContext.cs new file mode 100644 index 0000000..c0fc0ad --- /dev/null +++ b/src/Functions/Services/CallRecordsGraphContext.cs @@ -0,0 +1,530 @@ +using Azure.Core; +using CallRecordInsights.Extensions; +using CallRecordInsights.Models; +using Microsoft.Extensions.Logging; +using Microsoft.Graph; +using Microsoft.Graph.Models; +using Microsoft.Graph.Models.CallRecords; +using Microsoft.Kiota.Abstractions; +using System; +using System.Collections.Generic; +using System.IdentityModel.Tokens.Jwt; +using System.Linq; +using System.Net; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace CallRecordInsights.Services +{ + /// + /// A context for managing and for the configured + /// + public class CallRecordsGraphContext : ICallRecordsGraphContext + { + private readonly Lazy> lazyTenantList; + private readonly Lazy lazyNotificationUrlString; + private readonly Lazy lazyDefaultTenant; + + private readonly TokenCredential credential; + private readonly GraphServiceClient graphClient; + private readonly CallRecordsGraphOptions graphOptions; + private readonly ILogger logger; + + public CallRecordsGraphContext( + TokenCredential credential, + GraphServiceClient graphClient, + CallRecordsGraphOptions graphOptions, + ILogger logger) + { + this.credential = credential; + this.graphClient = graphClient; + this.graphOptions = graphOptions; + this.logger = logger; + + lazyDefaultTenant = new(DefaultTenantFactory); + lazyTenantList = new(TenantListFactory); + lazyNotificationUrlString = new(NotificationUrlStringFactory); + } + public string DefaultTenant { get => lazyDefaultTenant.Value; } + + /// + /// The configured Tenants to use for callRecord notifications found in the + /// If the is empty, then it will be set to a list of 1 tenant that is the default tenant + /// The default tenant is the tenantId associated with the current Azure Subscription + /// + public IReadOnlyList Tenants { get => lazyTenantList.Value; } + + /// + /// Adds or renews a for the configured for all configured tenants + /// + /// + /// + /// + public async Task> AddOrRenewSubscriptionsForConfiguredTenantsAsync(CancellationToken cancellationToken = default) + { + var results = new Dictionary(); + var errors = new List(); + + logger?.LogInformation("Adding or renewing subscriptions for all configured tenants"); + + foreach (var tenant in Tenants) + { + try + { + var subscription = await AddOrRenewSubscriptionsForTenantAsync( + tenant, + cancellationToken) + .ConfigureAwait(false); + + if (subscription is not default(Subscription)) + results.Add(tenant, subscription); + } + catch (Exception ex) when (ex is ApiException or TaskCanceledException or OperationCanceledException) + { + errors.Add(ex); + } + } + + if (errors.Any()) + throw new AggregateException("Errors adding or renewing subscriptions", errors); + + return results; + } + + /// + /// Gets all existing for the configured from all configured tenants + /// + /// + /// where the key is the tenantId in which the subscription was found, + /// and the value is the configured + /// + public async Task> GetSubscriptionsFromConfiguredTenantsAsync(CancellationToken cancellationToken = default) + { + var results = new Dictionary(); + var errors = new List(); + + logger?.LogInformation("Looking for subscriptions in all configured tenants"); + + foreach (var tenant in Tenants) + { + try + { + var subscription = await GetSubscriptionForTenantAsync( + tenant, + cancellationToken) + .ConfigureAwait(false); + + if (subscription is not default(Subscription)) + results.Add(tenant, subscription); + } + catch (Exception ex) when (ex is ApiException or TaskCanceledException or OperationCanceledException) + { + errors.Add(ex); + } + } + + if (errors.Any()) + throw new AggregateException("Errors getting subscriptions", errors); + + return results; + } + + /// + /// Looks for a callRecord in all configured tenants + /// + /// The id of the callRecord to retrieve + /// + /// where the key is the tenantId in which the callRecord was found, + /// and the value is the requested + /// + public async Task> GetCallRecordFromConfiguredTenantsAsync(string callId, CancellationToken cancellationToken = default) + { + var results = new Dictionary(StringComparer.OrdinalIgnoreCase); + var errors = new List(); + + logger?.LogInformation( + "Looking for callRecord {CallId} in all configured tenants", + callId?.Sanitize()); + + foreach (var tenant in Tenants) + { + try + { + var callRecord = await GetCallRecordFromTenantAsync( + callId, + tenant, + cancellationToken, + throwNotFoundException: false) + .ConfigureAwait(false); + + if (callRecord is not default(CallRecord)) + results.Add(tenant,callRecord); + } + catch (Exception ex) when (ex is TaskCanceledException or OperationCanceledException or ApiException) + { + errors.Add(ex); + } + } + + if (errors.Any()) + throw new AggregateException("Errors getting callRecord", errors); + + if (results.Count == 0) + logger?.LogWarning( + "CallRecord {CallId} not found in any configured tenants", + callId?.Sanitize()); + + return results; + } + + /// + /// Adds or renews a for the configured for a specific tenant + /// + /// + /// that was added or renewed + /// Thrown if is not found in the configuration after normalization + /// If the Graph call fails + /// + /// + public async Task AddOrRenewSubscriptionsForTenantAsync(string tenant, CancellationToken cancellationToken = default) + { + logger?.LogInformation( + "Adding or renewing subscriptions for '{Tenant}'", + tenant); + + var currentSubscription = await GetSubscriptionForTenantAsync( + tenant, + cancellationToken) + .ConfigureAwait(false); + + if (currentSubscription is default(Subscription)) + { + logger?.LogInformation( + "Subscription does not exist for '{Tenant}'", + tenant); + return await AddSubscriptionForTenantAsync( + tenant, + cancellationToken) + .ConfigureAwait(false); + } + + logger?.LogInformation( + "Subscription {id} already exists for '{Tenant}'", + currentSubscription.Id, + tenant); + + return await RenewSubscriptionForTenantAsync( + currentSubscription, + tenant, + cancellationToken) + .ConfigureAwait(false); + } + + /// + /// Gets an existing for the configured from a specific tenant + /// + /// The tenantId to get the subscription from + /// + /// that was found, or null if missing. + /// Thrown if is not found in the configuration after normalization + /// If the Graph call fails + /// + /// + public async Task GetSubscriptionForTenantAsync(string tenant, CancellationToken cancellationToken = default) + { + tenant = GetNormalizedTenantFromConfiguration(tenant); + + try + { + logger?.LogInformation( + "Getting subscription for '{Tenant}'", + tenant); + + var currentSubs = await graphClient.Subscriptions + .GetAsync( + r => r.Options.AsAppForTenant(tenant), + cancellationToken) + .ConfigureAwait(false); + + return currentSubs?.Value? + .FirstOrDefault(subscription => + subscription?.Resource == graphOptions.Resource + && subscription?.ChangeType == graphOptions.ChangeType + && Uri.TryCreate(subscription?.NotificationUrl, UriKind.Absolute, out var subscriptionUri) + && graphOptions.NotificationUrl.IsBaseOf(subscriptionUri)); + } + catch (Exception ex) when (ex is ApiException or TaskCanceledException or OperationCanceledException) + { + logger?.LogError( + ex, + "Error getting subscription for '{Tenant}'", + tenant); + + throw; + } + } + + /// + /// Renews an existing for the configured to a specific tenant + /// + /// The exisiting to be renewed + /// The tenantId in which the subscription exists + /// + /// that was renewed + /// Thrown if is not found in the configuration after normalization + /// If the Graph call fails + /// + /// + public async Task RenewSubscriptionForTenantAsync(Subscription existing, string tenant, CancellationToken cancellationToken = default) + { + tenant = GetNormalizedTenantFromConfiguration(tenant); + + try + { + logger?.LogInformation( + "Renewing subscription {id} for '{Tenant}'", + existing.Id, + tenant); + + var newSubscription = await graphClient.Subscriptions[existing.Id] + .PatchAsync( + GetSubscriptionRequest(), + r => r.Options.AsAppForTenant(tenant), + cancellationToken) + .ConfigureAwait(false); + + logger?.LogInformation( + "Subscription {id} renewed for '{Tenant}'", + newSubscription?.Id, + tenant); + + return newSubscription; + } + catch (Exception ex) when (ex is ApiException or TaskCanceledException or OperationCanceledException) + { + logger?.LogError( + ex, + "Error renewing subscription for '{Tenant}'", + tenant); + + throw; + } + } + + /// + /// Adds a new for the configured to a specific tenant + /// + /// The tenantId to add the subscription + /// + /// that was added + /// Thrown if is not found in the configuration after normalization + /// If the Graph call fails + /// + /// + public async Task AddSubscriptionForTenantAsync(string tenant, CancellationToken cancellationToken = default) + { + tenant = GetNormalizedTenantFromConfiguration(tenant); + + try + { + logger?.LogInformation( + "Adding subscription for '{Tenant}'", + tenant); + + var newSubscription = await graphClient.Subscriptions + .PostAsync( + GetSubscriptionRequest(), + r => r.Options.AsAppForTenant(tenant), + cancellationToken) + .ConfigureAwait(false); + + logger?.LogInformation( + "Subscription {id} added for '{Tenant}'", + newSubscription?.Id, + tenant); + + return newSubscription; + } + catch (Exception ex) when (ex is ApiException or TaskCanceledException or OperationCanceledException) + { + logger?.LogError( + ex, + "Error adding subscription for '{Tenant}'", + tenant); + + throw; + } + } + + /// + /// Gets a specific callRecord from a specific tenant + /// + /// The id of the specific callRecord to retrieve + /// The tenantId context to use to request the callReocrd + /// + /// Should this method throw exceptions or return null + /// that was requested + /// Thrown if is not found in the configuration after normalization + /// If the Graph call fails + /// + /// + public async Task GetCallRecordFromTenantAsync(string callId, string tenant, CancellationToken cancellationToken = default, bool throwNotFoundException = true) + { + tenant = GetNormalizedTenantFromConfiguration(tenant); + + try + { + logger?.LogInformation( + "Looking for callRecord {CallId} in '{Tenant}'", + callId?.Sanitize(), + tenant); + + var callRecord = await graphClient.Communications.CallRecords[callId] + .GetAsync( + r => + { + r.QueryParameters.Expand = new[] { "sessions($expand=segments)" }; + r.Options.AsAppForTenant(tenant); + }, + cancellationToken) + .ConfigureAwait(false); + + logger?.LogInformation( + "Found callRecord {CallId} with {SessionCount} sessions in '{Tenant}'", + callId?.Sanitize(), + callRecord?.Sessions?.Count, + tenant); + + return callRecord; + } + catch (Exception ex) when (ex is ApiException or TaskCanceledException or OperationCanceledException) + { + if (!throwNotFoundException && ex is ApiException apiEx && apiEx.ResponseStatusCode == (int)HttpStatusCode.NotFound) + { + // Ignore Not Found errors + logger?.LogWarning( + "CallRecord {CallId} was not found in tenant {Tenant}", + callId?.Sanitize(), + tenant); + + return default; + } + + logger?.LogError( + ex, + "Errors getting CallRecord {CallId} from '{Tenant}'", + callId?.Sanitize(), + tenant); + + throw; + } + } + + /// + /// Get a request object for the configured + /// + /// + private Subscription GetSubscriptionRequest() + { + var subscription = new Subscription() + { + ChangeType = graphOptions.ChangeType, + NotificationUrl = lazyNotificationUrlString.Value, + Resource = graphOptions.Resource, + ExpirationDateTime = DateTime.UtcNow.AddMinutes(graphOptions.LifetimeMinutes) + }; + + logger?.LogInformation( + "Created Subscription request for {Resource} {ChangeType} notifications with url {NotificationUrl} expiring at {ExpirationDateTime}", + subscription.Resource, + subscription.ChangeType, + subscription.NotificationUrl, + subscription.ExpirationDateTime); + + return subscription; + } + + /// + /// Gets the Guid string representation of the from the configuration. + /// Throws if is not found in the configuration after normalization + /// + /// + /// The normalized Guid string representation of + /// Thrown if is not found in the configuration after normalization + private string GetNormalizedTenantFromConfiguration(string tenantIdentifier) + { + tenantIdentifier = tenantIdentifier?.TryGetValidTenantIdGuid(out var tenantIdGuid) == true + ? tenantIdGuid.ToString() + : Tenants[0]; + + if (!Tenants.Contains(tenantIdentifier, StringComparer.OrdinalIgnoreCase)) + { + logger?.LogError( + "Tenant '{Tenant}' is not configured", + tenantIdentifier); + + throw new ArgumentException("{Tenant} is not configured", nameof(tenantIdentifier)); + } + + return tenantIdentifier; + } + + /// + /// Gets the notification url string for the configured + /// + /// + private string NotificationUrlStringFactory() + { + var queryBuilder = new StringBuilder(graphOptions.NotificationUrl.Query); + if (queryBuilder.Length > 0) + queryBuilder.Append('&'); + var url = new UriBuilder(graphOptions.NotificationUrl) { Query = queryBuilder.Append("tenantId=").Append(DefaultTenant).ToString() }.Uri.ToString(); + if (url.StartsWith("eventhub:")) + url = $"EventHub:{url[9..]}"; + return url; + } + + /// + /// Gets the list of tenants from the configured + /// + /// + private List TenantListFactory() + { + var tenants = graphOptions + .Tenants? + .Select(t => t.TryGetValidTenantIdGuid(out var tid) ? tid.ToString() : null) + .Where(t => !string.IsNullOrEmpty(t)) + .Distinct() + .ToList(); + + // If graphOptions.Tenants is not empty, then it will be used as it was passed + // if the default tenant was not included in the list, then it will not be configured for callRecord notifications + if (tenants?.Count > 0) + return tenants; + + // If graphOptions.Tenants list is empty, then it will be set to a list of 1 tenant that is the default tenant + return new List { DefaultTenant }; + } + + /// + /// Gets the default tenantId associated with the current Azure Subscription + /// + /// + private string DefaultTenantFactory() + { + var token = credential.GetToken( + new TokenRequestContext(new[] { $"https://{graphOptions.Endpoint}/.default" }), + default) + .Token; + var tenantId = new JwtSecurityToken(token) + .Claims + .FirstOrDefault(c => c.Type == "tid")? + .Value? + .TryGetValidTenantIdGuid(out var tenantIdGuid) == true + ? tenantIdGuid.ToString() + : null; + return tenantId; + } + } +} diff --git a/src/Functions/Services/ICallRecordsDataContext.cs b/src/Functions/Services/ICallRecordsDataContext.cs new file mode 100644 index 0000000..f8f8498 --- /dev/null +++ b/src/Functions/Services/ICallRecordsDataContext.cs @@ -0,0 +1,17 @@ +using CallRecordInsights.Models; +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; + +namespace CallRecordInsights.Services +{ + public interface ICallRecordsDataContext + { + string Endpoint { get; } + + Task CreateOrUpsertProcessedRecordsAsync(IReadOnlyList cosmosCallRecords, string tenantIdContext, Guid callIdGuid, CallRecordsDataContext.Operation operation, CancellationToken cancellationToken = default); + Task GetNeededProcessedRecordsOperationAsync(string tenantIdContext, Guid callId, DateTimeOffset? lastModified, int count, CancellationToken cancellationToken = default); + Task IsAccessible(CancellationToken cancellationToken = default); + } +} \ No newline at end of file diff --git a/src/Functions/Services/ICallRecordsGraphContext.cs b/src/Functions/Services/ICallRecordsGraphContext.cs new file mode 100644 index 0000000..a5e6444 --- /dev/null +++ b/src/Functions/Services/ICallRecordsGraphContext.cs @@ -0,0 +1,24 @@ +using Microsoft.Graph.Models; +using Microsoft.Graph.Models.CallRecords; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; + +namespace CallRecordInsights.Services +{ + /// + /// An interface for the context for managing and objects. + /// + public interface ICallRecordsGraphContext + { + IReadOnlyList Tenants { get; } + Task> AddOrRenewSubscriptionsForConfiguredTenantsAsync(CancellationToken cancellationToken = default); + Task> GetSubscriptionsFromConfiguredTenantsAsync(CancellationToken cancellationToken = default); + Task> GetCallRecordFromConfiguredTenantsAsync(string callId, CancellationToken cancellationToken = default); + Task AddOrRenewSubscriptionsForTenantAsync(string tenant, CancellationToken cancellationToken = default); + Task AddSubscriptionForTenantAsync(string tenant, CancellationToken cancellationToken = default); + Task GetCallRecordFromTenantAsync(string callId, string tenant, CancellationToken cancellationToken = default, bool logNotFoundErrors = true); + Task GetSubscriptionForTenantAsync(string tenant, CancellationToken cancellationToken = default); + Task RenewSubscriptionForTenantAsync(Subscription existing, string tenant, CancellationToken cancellationToken = default); + } +} \ No newline at end of file diff --git a/src/Functions/Startup.cs b/src/Functions/Startup.cs new file mode 100644 index 0000000..4c2c39a --- /dev/null +++ b/src/Functions/Startup.cs @@ -0,0 +1,30 @@ +using CallRecordInsights.Extensions; +using Microsoft.Azure.Functions.Extensions.DependencyInjection; +using Microsoft.Extensions.Configuration; +using System.IO; + +[assembly: FunctionsStartup(typeof(CallRecordInsights.Startup))] + +namespace CallRecordInsights +{ + public class Startup : FunctionsStartup + { + public override void ConfigureAppConfiguration(IFunctionsConfigurationBuilder builder) + { + var context = builder.GetContext(); + + builder.ConfigurationBuilder + .AddJsonFile(Path.Combine(context.ApplicationRootPath, "appsettings.json"), optional: true, reloadOnChange: false) + .AddJsonFile(Path.Combine(context.ApplicationRootPath, $"appsettings.{context.EnvironmentName}.json"), optional: true, reloadOnChange: false) + .AddEnvironmentVariables(); + } + + public override void Configure(IFunctionsHostBuilder builder) + { + builder.Services + .AddJsonToKustoFlattener() + .AddCallRecordsGraphContext() + .AddCallRecordsDataContext(); + } + } +} diff --git a/src/Functions/appsettings.development.json b/src/Functions/appsettings.development.json new file mode 100644 index 0000000..40a35b4 --- /dev/null +++ b/src/Functions/appsettings.development.json @@ -0,0 +1,7 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Trace" + } + } +} diff --git a/src/Functions/appsettings.json b/src/Functions/appsettings.json new file mode 100644 index 0000000..8983e0f --- /dev/null +++ b/src/Functions/appsettings.json @@ -0,0 +1,9 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft": "Warning", + "Microsoft.Hosting.Lifetime": "Information" + } + } +} diff --git a/src/Functions/host.json b/src/Functions/host.json new file mode 100644 index 0000000..e570a71 --- /dev/null +++ b/src/Functions/host.json @@ -0,0 +1,41 @@ +{ + "version": "2.0", + "logging": { + "fileLoggingMode": "always", + "logLevel": { + "default": "Information", + "Host.Results": "Error" + }, + "applicationInsights": { + "samplingSettings": { + "isEnabled": true, + "excludedTypes": "Request" + } + } + }, + "extensions": { + "eventHubs": { + "maxEventBatchSize": 100, + "batchCheckpointFrequency": 1, + "prefetchCount": 300, + "transportType": "amqpWebSockets", + "initialOffsetOptions": { + "type": "fromStart", + "enqueuedTimeUtc": "" + }, + "clientRetryOptions": { + "mode": "exponential", + "tryTimeout": "00:01:00", + "delay": "00:00:00.80" + } + }, + "queues": { + "maxPollingInterval": "00:00:02", + "visibilityTimeout": "00:00:30", + "batchSize": 16, + "maxDequeueCount": 5, + "newBatchThreshold": 8, + "messageEncoding": "base64" + } + } +}