diff --git a/CompanyCommunicator_Context.tm7 b/CompanyCommunicator_Context.tm7 new file mode 100644 index 000000000..4eba3cfa3 --- /dev/null +++ b/CompanyCommunicator_Context.tm7 @@ -0,0 +1,135 @@ +DRAWINGSURFACE418b6a60-9f3a-42a7-9a39-8ef51ee8c0d2DiagramNameDiagram 1DRAWINGSURFACE92e00741-0e95-4a75-b38d-2153cf978db5GE.EI92e00741-0e95-4a75-b38d-2153cf978db5Human UserNameHuman UserOut Of Scope71f3d9aa-b8ef-4e54-8126-607a1d903103falseReason For Out Of Scope752473b6-52d4-4776-9a24-202153f7d579Predefined Static AttributesTypetypeHuman0Configurable AttributesAs Generic External InteractorAuthenticates ItselfauthenticatesItselfNot ApplicableNoYes0MicrosoftMSNoYes0SE.EI.TMCore.User100461242100837fee15-1f67-4add-b2e8-cb602f6567ddGE.EI837fee15-1f67-4add-b2e8-cb602f6567ddExternal Web ApplicationNameTeams AppOut Of Scope71f3d9aa-b8ef-4e54-8126-607a1d903103falseReason For Out Of Scope752473b6-52d4-4776-9a24-202153f7d579Predefined Static AttributesTypetypeCode0Configurable AttributesAs Generic External InteractorAuthenticates ItselfauthenticatesItselfNot ApplicableNoYes0MicrosoftMSNoYes0SE.EI.TMCore.WebApp10017818010017e8d0b4-e1a3-4d53-a55a-8ebdcff76c2eGE.EI17e8d0b4-e1a3-4d53-a55a-8ebdcff76c2eExternal Web ServiceNameSMBA (Bot Framework)Out Of Scope71f3d9aa-b8ef-4e54-8126-607a1d903103falseReason For Out Of Scope752473b6-52d4-4776-9a24-202153f7d579Predefined Static AttributesTypetypeCode0Configurable AttributesAs Generic External InteractorAuthenticates ItselfauthenticatesItselfNot ApplicableNoYes0MicrosoftMSNoYes0SE.EI.TMCore.WebSvc100353178100f39b41ff-538a-4f04-b911-ba7a2fe73fa2GE.DSf39b41ff-538a-4f04-b911-ba7a2fe73fa2Non Relational DatabaseNameAzure Table StorageOut Of Scope71f3d9aa-b8ef-4e54-8126-607a1d903103falseReason For Out Of Scope752473b6-52d4-4776-9a24-202153f7d579Predefined Static AttributesStore TypestoreTypeNon Relational Database0Configurable AttributesAs Generic Data StoreStores CredentialsstoresCredentialsNoYes0Stores Log DatastoresLogDataNoYes0EncryptedEncryptedNoYes0SignedSignedNoYes0Write AccessAccessTypeNoYes0Removable StorageRemoveableStorageNoYes0BackupBackupNoYes0SharedsharedNoYes0SE.DS.TMCore.NoSQL1008291207100d8fe453f-286e-4fec-b7c1-33c9a1e56d4cGE.DSd8fe453f-286e-4fec-b7c1-33c9a1e56d4cCloud StorageNameApplication InsightsOut Of Scope71f3d9aa-b8ef-4e54-8126-607a1d903103falseReason For Out Of Scope752473b6-52d4-4776-9a24-202153f7d579Configurable AttributesAs Generic Data StoreStores CredentialsstoresCredentialsNoYes0Stores Log DatastoresLogDataNoYes0EncryptedEncryptedNoYes0SignedSignedNoYes0Write AccessAccessTypeNoYes0Removable StorageRemoveableStorageNoYes0BackupBackupNoYes0SharedsharedNoYes0Store TypestoreTypeSQL Relational DatabaseNon Relational DatabaseFile SystemRegistryConfigurationCacheHTML5 StorageCookieDevice0SE.DS.TMCore.CloudStorage10082919010005fec340-05db-4922-946d-112ff7373c03GE.P05fec340-05db-4922-946d-112ff7373c03Web ApplicationNameCompany CommunicatorOut Of Scope71f3d9aa-b8ef-4e54-8126-607a1d903103falseReason For Out Of Scope752473b6-52d4-4776-9a24-202153f7d579Predefined Static AttributesCode TypecodeTypeUnmanaged0Configurable AttributesAs Generic ProcessRunning AsrunningAsNot SelectedKernelSystemNetwork ServiceLocal ServiceAdministratorStandard User With ElevationStandard User Without ElevationWindows Store App0Isolation LevelIsolationNot SelectedAppContainerLow Integrity LevelMicrosoft Office Isolated Conversion Environment (MOICE)Sandbox0Accepts Input FromacceptsInputFromNot SelectedAny Remote User or EntityKernel, System, or Local AdminLocal or Network ServiceLocal Standard User With ElevationLocal Standard User Without ElevationWindows Store Apps or App Container ProcessesNothingOther0Implements or Uses an Authentication MechanismimplementsAuthenticationSchemeNoYes0Implements or Uses an Authorization MechanismimplementsCustomAuthorizationMechanismNoYes0Implements or Uses a Communication ProtocolimplementsCommunicationProtocolNoYes0Sanitizes InputhasInputSanitizersNot SelectedYesNo0Sanitizes OutputhasOutputSanitizersNot SelectedYesNo0SE.P.TMCore.WebApp100555123310078cb7043-4910-4f9e-8544-e7b2153dff3eGE.P78cb7043-4910-4f9e-8544-e7b2153dff3eManaged ApplicationNameService BusOut Of Scope71f3d9aa-b8ef-4e54-8126-607a1d903103falseReason For Out Of Scope752473b6-52d4-4776-9a24-202153f7d579Predefined Static AttributesCode TypecodeTypeManaged0Configurable AttributesAs Generic ProcessRunning AsrunningAsNot SelectedKernelSystemNetwork ServiceLocal ServiceAdministratorStandard User With ElevationStandard User Without ElevationWindows Store App0Isolation LevelIsolationNot SelectedAppContainerLow Integrity LevelMicrosoft Office Isolated Conversion Environment (MOICE)Sandbox0Accepts Input FromacceptsInputFromNot SelectedAny Remote User or EntityKernel, System, or Local AdminLocal or Network ServiceLocal Standard User With ElevationLocal Standard User Without ElevationWindows Store Apps or App Container ProcessesNothingOther0Implements or Uses an Authentication MechanismimplementsAuthenticationSchemeNoYes0Implements or Uses an Authorization MechanismimplementsCustomAuthorizationMechanismNoYes0Implements or Uses a Communication ProtocolimplementsCommunicationProtocolNoYes0Sanitizes InputhasInputSanitizersNot SelectedYesNo0Sanitizes OutputhasOutputSanitizersNot SelectedYesNo0SE.P.TMCore.NetApp10042012461006480d8e0-a4f9-4cc4-90ab-d5ab2a4d4e76GE.P6480d8e0-a4f9-4cc4-90ab-d5ab2a4d4e76Web ServiceNameAzure FunctionOut Of Scope71f3d9aa-b8ef-4e54-8126-607a1d903103falseReason For Out Of Scope752473b6-52d4-4776-9a24-202153f7d579Predefined Static AttributesCode TypecodeTypeUnmanaged0Configurable AttributesAs Generic ProcessRunning AsrunningAsNot SelectedKernelSystemNetwork ServiceLocal ServiceAdministratorStandard User With ElevationStandard User Without ElevationWindows Store App0Isolation LevelIsolationNot SelectedAppContainerLow Integrity LevelMicrosoft Office Isolated Conversion Environment (MOICE)Sandbox0Accepts Input FromacceptsInputFromNot SelectedAny Remote User or EntityKernel, System, or Local AdminLocal or Network ServiceLocal Standard User With ElevationLocal Standard User Without ElevationWindows Store Apps or App Container ProcessesNothingOther0Implements or Uses an Authentication MechanismimplementsAuthenticationSchemeNoYes0Implements or Uses an Authorization MechanismimplementsCustomAuthorizationMechanismNoYes0Implements or Uses a Communication ProtocolimplementsCommunicationProtocolNoYes0Sanitizes InputhasInputSanitizersNot SelectedYesNo0Sanitizes OutputhasOutputSanitizersNot SelectedYesNo0SE.P.TMCore.WebSvc10024013911002f23a6eb-aa7a-425c-9d2f-07a6d7ef6a18GE.P2f23a6eb-aa7a-425c-9d2f-07a6d7ef6a18Web ServiceNameMicrosoft GraphOut Of Scope71f3d9aa-b8ef-4e54-8126-607a1d903103falseReason For Out Of Scope752473b6-52d4-4776-9a24-202153f7d579Predefined Static AttributesCode TypecodeTypeUnmanaged0Configurable AttributesAs Generic ProcessRunning AsrunningAsNot SelectedKernelSystemNetwork ServiceLocal ServiceAdministratorStandard User With ElevationStandard User Without ElevationWindows Store App0Isolation LevelIsolationNot SelectedAppContainerLow Integrity LevelMicrosoft Office Isolated Conversion Environment (MOICE)Sandbox0Accepts Input FromacceptsInputFromNot SelectedAny Remote User or EntityKernel, System, or Local AdminLocal or Network ServiceLocal Standard User With ElevationLocal Standard User Without ElevationWindows Store Apps or App Container ProcessesNothingOther0Implements or Uses an Authentication MechanismimplementsAuthenticationSchemeNoYes0Implements or Uses an Authorization MechanismimplementsCustomAuthorizationMechanismNoYes0Implements or Uses a Communication ProtocolimplementsCommunicationProtocolNoYes0Sanitizes InputhasInputSanitizersNot SelectedYesNo0Sanitizes OutputhasOutputSanitizersNot SelectedYesNo0SE.P.TMCore.WebSvc100593146210063a3b273-2c3b-40ef-bc41-ae67e941c8bdGE.DS63a3b273-2c3b-40ef-bc41-ae67e941c8bdNon Relational DatabaseNameAzure Key VaultOut Of Scope71f3d9aa-b8ef-4e54-8126-607a1d903103falseReason For Out Of Scope752473b6-52d4-4776-9a24-202153f7d579Predefined Static AttributesStore TypestoreTypeNon Relational Database0Configurable AttributesAs Generic Data StoreStores CredentialsstoresCredentialsNoYes0Stores Log DatastoresLogDataNoYes0EncryptedEncryptedNoYes0SignedSignedNoYes0Write AccessAccessTypeNoYes0Removable StorageRemoveableStorageNoYes0BackupBackupNoYes0SharedsharedNoYes0SE.DS.TMCore.NoSQL100702010100
Diagram 1
b11fc5fb-f7af-441d-9e05-52b3755d9509GE.DFb11fc5fb-f7af-441d-9e05-52b3755d9509HTTPSName1. User interacts with app in TeamsDataflow Order15ccd509-98eb-49ad-b9c2-b4a2926d17800Out Of Scope71f3d9aa-b8ef-4e54-8126-607a1d903103falseReason For Out Of Scope752473b6-52d4-4776-9a24-202153f7d579Predefined Static AttributesDestination AuthenticatedauthenticatesDestinationYes0Provides ConfidentialityprovidesConfidentialityYes0Provides IntegrityprovidesIntegrityYes0Configurable AttributesAs Generic Data FlowPhysical NetworkchannelNot SelectedWireWi-FiBluetooth2G-4G0Source AuthenticatedauthenticatesSourceNot SelectedNoYes0Transmits XMLXMLencNoYes0Contains CookiesCookiesYesNo0SOAP PayloadSOAPNoYes0REST PayloadRESTNoYes0RSS PayloadRSSNoYes0JSON PayloadJSONNoYes0Forgery Protection54851a3b-65da-4902-b4e0-94ef015be735Not SelectedValidateAntiForgeryTokenAttributeViewStateUserKeyNonceOther dynamic canaryStatic header not available to the browserOtherNoneNot applicable because the request does not change data0SE.DF.TMCore.HTTPS168210EastWest92e00741-0e95-4a75-b38d-2153cf978db5141292837fee15-1f67-4add-b2e8-cb602f6567dd183130f0d0ff30-4d82-4acc-8794-05aff33a45f1GE.DFf0d0ff30-4d82-4acc-8794-05aff33a45f1HTTPSName2.Teams sends activities +[CC, EUII, EUPI, OII]Dataflow Order15ccd509-98eb-49ad-b9c2-b4a2926d17800Out Of Scope71f3d9aa-b8ef-4e54-8126-607a1d903103trueReason For Out Of Scope752473b6-52d4-4776-9a24-202153f7d579Covered by threat model of bots in Teams Predefined Static AttributesDestination AuthenticatedauthenticatesDestinationYes0Provides ConfidentialityprovidesConfidentialityYes0Provides IntegrityprovidesIntegrityYes0Configurable AttributesAs Generic Data FlowPhysical NetworkchannelNot SelectedWireWi-FiBluetooth2G-4G0Source AuthenticatedauthenticatesSourceNot SelectedNoYes0Transmits XMLXMLencNoYes0Contains CookiesCookiesYesNo0SOAP PayloadSOAPNoYes0REST PayloadRESTNoYes0RSS PayloadRSSNoYes0JSON PayloadJSONNoYes0Forgery Protection54851a3b-65da-4902-b4e0-94ef015be735Not SelectedValidateAntiForgeryTokenAttributeViewStateUserKeyNonceOther dynamic canaryStatic header not available to the browserOtherNoneNot applicable because the request does not change data0SE.DF.TMCore.HTTPS31925EastWest837fee15-1f67-4add-b2e8-cb602f6567dd27313017e8d0b4-e1a3-4d53-a55a-8ebdcff76c2e3581283848cb23-93ed-4266-91f4-4d638eab2a31GE.DF3848cb23-93ed-4266-91f4-4d638eab2a31HTTPSName3.Bot activities +HTTPS; SMBA -> bot token +[CC, EUII, EUPDataflow Order15ccd509-98eb-49ad-b9c2-b4a2926d17800Out Of Scope71f3d9aa-b8ef-4e54-8126-607a1d903103falseReason For Out Of Scope752473b6-52d4-4776-9a24-202153f7d579Predefined Static AttributesDestination AuthenticatedauthenticatesDestinationYes0Provides ConfidentialityprovidesConfidentialityYes0Provides IntegrityprovidesIntegrityYes0Configurable AttributesAs Generic Data FlowPhysical NetworkchannelNot SelectedWireWi-FiBluetooth2G-4G0Source AuthenticatedauthenticatesSourceNot SelectedNoYes0Transmits XMLXMLencNoYes0Contains CookiesCookiesYesNo0SOAP PayloadSOAPNoYes0REST PayloadRESTNoYes0RSS PayloadRSSNoYes0JSON PayloadJSONNoYes0Forgery Protection54851a3b-65da-4902-b4e0-94ef015be735Not SelectedValidateAntiForgeryTokenAttributeViewStateUserKeyNonceOther dynamic canaryStatic header not available to the browserOtherNoneNot applicable because the request does not change data0SE.DF.TMCore.HTTPS51115EastNorthWest00000000-0000-0000-0000-00000000000044812805fec340-05db-4922-946d-112ff7373c03573251d692dfd7-b8cf-4757-9753-6ac27d34e69dGE.DFd692dfd7-b8cf-4757-9753-6ac27d34e69dHTTPSName7. Queue the message +HTTPS; Managed Identity[SM]Dataflow Order15ccd509-98eb-49ad-b9c2-b4a2926d17800Out Of Scope71f3d9aa-b8ef-4e54-8126-607a1d903103falseReason For Out Of Scope752473b6-52d4-4776-9a24-202153f7d579Predefined Static AttributesDestination AuthenticatedauthenticatesDestinationYes0Provides ConfidentialityprovidesConfidentialityYes0Provides IntegrityprovidesIntegrityYes0Configurable AttributesAs Generic Data FlowPhysical NetworkchannelNot SelectedWireWi-FiBluetooth2G-4G0Source AuthenticatedauthenticatesSourceNot SelectedNoYes0Transmits XMLXMLencNoYes0Contains CookiesCookiesYesNo0SOAP PayloadSOAPNoYes0REST PayloadRESTNoYes0RSS PayloadRSSNoYes0JSON PayloadJSONNoYes0Forgery Protection54851a3b-65da-4902-b4e0-94ef015be735Not SelectedValidateAntiForgeryTokenAttributeViewStateUserKeyNonceOther dynamic canaryStatic header not available to the browserOtherNoneNot applicable because the request does not change data0SE.DF.TMCore.HTTPS467187NorthNorth05fec340-05db-4922-946d-112ff7373c0360523978cb7043-4910-4f9e-8544-e7b2153dff3e4702523b63b270-d39a-4d5f-9df4-33665a91d32bGE.DF3b63b270-d39a-4d5f-9df4-33665a91d32bHTTPSName12.Queue the message HTTPS; +Managed Identity [SM]Dataflow Order15ccd509-98eb-49ad-b9c2-b4a2926d17800Out Of Scope71f3d9aa-b8ef-4e54-8126-607a1d903103falseReason For Out Of Scope752473b6-52d4-4776-9a24-202153f7d579Predefined Static AttributesDestination AuthenticatedauthenticatesDestinationYes0Provides ConfidentialityprovidesConfidentialityYes0Provides IntegrityprovidesIntegrityYes0Configurable AttributesAs Generic Data FlowPhysical NetworkchannelNot SelectedWireWi-FiBluetooth2G-4G0Source AuthenticatedauthenticatesSourceNot SelectedNoYes0Transmits XMLXMLencNoYes0Contains CookiesCookiesYesNo0SOAP PayloadSOAPNoYes0REST PayloadRESTNoYes0RSS PayloadRSSNoYes0JSON PayloadJSONNoYes0Forgery Protection54851a3b-65da-4902-b4e0-94ef015be735Not SelectedValidateAntiForgeryTokenAttributeViewStateUserKeyNonceOther dynamic canaryStatic header not available to the browserOtherNoneNot applicable because the request does not change data0SE.DF.TMCore.HTTPS342324NorthWest6480d8e0-a4f9-4cc4-90ab-d5ab2a4d4e7629039778cb7043-4910-4f9e-8544-e7b2153dff3e425296273c0d07-97af-4fa8-8a6d-756d72076e19GE.DF273c0d07-97af-4fa8-8a6d-756d72076e19HTTPSName8. App Trigger over HTTPSDataflow Order15ccd509-98eb-49ad-b9c2-b4a2926d17800Out Of Scope71f3d9aa-b8ef-4e54-8126-607a1d903103falseReason For Out Of Scope752473b6-52d4-4776-9a24-202153f7d579Predefined Static AttributesDestination AuthenticatedauthenticatesDestinationYes0Provides ConfidentialityprovidesConfidentialityYes0Provides IntegrityprovidesIntegrityYes0Configurable AttributesAs Generic Data FlowPhysical NetworkchannelNot SelectedWireWi-FiBluetooth2G-4G0Source AuthenticatedauthenticatesSourceNot SelectedNoYes0Transmits XMLXMLencNoYes0Contains CookiesCookiesYesNo0SOAP PayloadSOAPNoYes0REST PayloadRESTNoYes0RSS PayloadRSSNoYes0JSON PayloadJSONNoYes0Forgery Protection54851a3b-65da-4902-b4e0-94ef015be735Not SelectedValidateAntiForgeryTokenAttributeViewStateUserKeyNonceOther dynamic canaryStatic header not available to the browserOtherNoneNot applicable because the request does not change data0SE.DF.TMCore.HTTPS464366EastEast78cb7043-4910-4f9e-8544-e7b2153dff3e5152966480d8e0-a4f9-4cc4-90ab-d5ab2a4d4e76335441059e20ab-f3df-4db4-94d7-e3c0fd81d905GE.DF059e20ab-f3df-4db4-94d7-e3c0fd81d905HTTPSName6.Read data HTTPS; +delegated tokenDataflow Order15ccd509-98eb-49ad-b9c2-b4a2926d17800Out Of Scope71f3d9aa-b8ef-4e54-8126-607a1d903103falseReason For Out Of Scope752473b6-52d4-4776-9a24-202153f7d579Predefined Static AttributesDestination AuthenticatedauthenticatesDestinationYes0Provides ConfidentialityprovidesConfidentialityYes0Provides IntegrityprovidesIntegrityYes0Configurable AttributesAs Generic Data FlowPhysical NetworkchannelNot SelectedWireWi-FiBluetooth2G-4G0Source AuthenticatedauthenticatesSourceNot SelectedNoYes0Transmits XMLXMLencNoYes0Contains CookiesCookiesYesNo0SOAP PayloadSOAPNoYes0REST PayloadRESTNoYes0RSS PayloadRSSNoYes0JSON PayloadJSONNoYes0Forgery Protection54851a3b-65da-4902-b4e0-94ef015be735Not SelectedValidateAntiForgeryTokenAttributeViewStateUserKeyNonceOther dynamic canaryStatic header not available to the browserOtherNoneNot applicable because the request does not change data0SE.DF.TMCore.HTTPS636382SouthNorth05fec340-05db-4922-946d-112ff7373c036053282f23a6eb-aa7a-425c-9d2f-07a6d7ef6a186434685c421ce7-b8d7-42c2-89e0-8eebc61fc6bbGE.DF5c421ce7-b8d7-42c2-89e0-8eebc61fc6bbHTTPSName13. Log telemetry +HTTPS; API key +[EUPI, SM]Dataflow Order15ccd509-98eb-49ad-b9c2-b4a2926d17800Out Of Scope71f3d9aa-b8ef-4e54-8126-607a1d903103falseReason For Out Of Scope752473b6-52d4-4776-9a24-202153f7d579Predefined Static AttributesDestination AuthenticatedauthenticatesDestinationYes0Provides ConfidentialityprovidesConfidentialityYes0Provides IntegrityprovidesIntegrityYes0Configurable AttributesAs Generic Data FlowPhysical NetworkchannelNot SelectedWireWi-FiBluetooth2G-4G0Source AuthenticatedauthenticatesSourceNot SelectedNoYes0Transmits XMLXMLencNoYes0Contains CookiesCookiesYesNo0SOAP PayloadSOAPNoYes0REST PayloadRESTNoYes0RSS PayloadRSSNoYes0JSON PayloadJSONNoYes0Forgery Protection54851a3b-65da-4902-b4e0-94ef015be735Not SelectedValidateAntiForgeryTokenAttributeViewStateUserKeyNonceOther dynamic canaryStatic header not available to the browserOtherNoneNot applicable because the request does not change data0SE.DF.TMCore.HTTPS723172SouthEastWest05fec340-05db-4922-946d-112ff7373c03636314d8fe453f-286e-4fec-b7c1-33c9a1e56d4c834140d3145983-ea29-4e12-8ba6-24b6792eb8f6GE.DFd3145983-ea29-4e12-8ba6-24b6792eb8f6HTTPSName5. Read/update data +HTTPS; connection string +[CC, EUII, EUPIDataflow Order15ccd509-98eb-49ad-b9c2-b4a2926d17800Out Of Scope71f3d9aa-b8ef-4e54-8126-607a1d903103falseReason For Out Of Scope752473b6-52d4-4776-9a24-202153f7d579Predefined Static AttributesDestination AuthenticatedauthenticatesDestinationYes0Provides ConfidentialityprovidesConfidentialityYes0Provides IntegrityprovidesIntegrityYes0Configurable AttributesAs Generic Data FlowPhysical NetworkchannelNot SelectedWireWi-FiBluetooth2G-4G0Source AuthenticatedauthenticatesSourceNot SelectedNoYes0Transmits XMLXMLencNoYes0Contains CookiesCookiesYesNo0SOAP PayloadSOAPNoYes0REST PayloadRESTNoYes0RSS PayloadRSSNoYes0JSON PayloadJSONNoYes0Forgery Protection54851a3b-65da-4902-b4e0-94ef015be735Not SelectedValidateAntiForgeryTokenAttributeViewStateUserKeyNonceOther dynamic canaryStatic header not available to the browserOtherNoneNot applicable because the request does not change data0SE.DF.TMCore.HTTPS741298EastWest05fec340-05db-4922-946d-112ff7373c03650283f39b41ff-538a-4f04-b911-ba7a2fe73fa2834257c47fbb19-55fe-45a0-883a-1dcb4f3e12b4GE.DFc47fbb19-55fe-45a0-883a-1dcb4f3e12b4HTTPSName10. Read/update data +HTTPS; connection string +[CC, EUII, EUPIDataflow Order15ccd509-98eb-49ad-b9c2-b4a2926d17800Out Of Scope71f3d9aa-b8ef-4e54-8126-607a1d903103falseReason For Out Of Scope752473b6-52d4-4776-9a24-202153f7d579Predefined Static AttributesDestination AuthenticatedauthenticatesDestinationYes0Provides ConfidentialityprovidesConfidentialityYes0Provides IntegrityprovidesIntegrityYes0Configurable AttributesAs Generic Data FlowPhysical NetworkchannelNot SelectedWireWi-FiBluetooth2G-4G0Source AuthenticatedauthenticatesSourceNot SelectedNoYes0Transmits XMLXMLencNoYes0Contains CookiesCookiesYesNo0SOAP PayloadSOAPNoYes0REST PayloadRESTNoYes0RSS PayloadRSSNoYes0JSON PayloadJSONNoYes0Forgery Protection54851a3b-65da-4902-b4e0-94ef015be735Not SelectedValidateAntiForgeryTokenAttributeViewStateUserKeyNonceOther dynamic canaryStatic header not available to the browserOtherNoneNot applicable because the request does not change data0SE.DF.TMCore.HTTPS844396NorthEastSouth6480d8e0-a4f9-4cc4-90ab-d5ab2a4d4e76321409f39b41ff-538a-4f04-b911-ba7a2fe73fa2879302f3f99a81-3930-4708-b3b6-a71786518de5GE.DFf3f99a81-3930-4708-b3b6-a71786518de5HTTPSName11. Post Message to User HTTPSDataflow Order15ccd509-98eb-49ad-b9c2-b4a2926d17800Out Of Scope71f3d9aa-b8ef-4e54-8126-607a1d903103falseReason For Out Of Scope752473b6-52d4-4776-9a24-202153f7d579Predefined Static AttributesDestination AuthenticatedauthenticatesDestinationYes0Provides ConfidentialityprovidesConfidentialityYes0Provides IntegrityprovidesIntegrityYes0Configurable AttributesAs Generic Data FlowPhysical NetworkchannelNot SelectedWireWi-FiBluetooth2G-4G0Source AuthenticatedauthenticatesSourceNot SelectedNoYes0Transmits XMLXMLencNoYes0Contains CookiesCookiesYesNo0SOAP PayloadSOAPNoYes0REST PayloadRESTNoYes0RSS PayloadRSSNoYes0JSON PayloadJSONNoYes0Forgery Protection54851a3b-65da-4902-b4e0-94ef015be735Not SelectedValidateAntiForgeryTokenAttributeViewStateUserKeyNonceOther dynamic canaryStatic header not available to the browserOtherNoneNot applicable because the request does not change data0SE.DF.TMCore.HTTPS252260WestSouth6480d8e0-a4f9-4cc4-90ab-d5ab2a4d4e7624544117e8d0b4-e1a3-4d53-a55a-8ebdcff76c2e403173433a9d8a-84b0-4846-a972-5394dffe3529GE.DF433a9d8a-84b0-4846-a972-5394dffe3529HTTPSName9.Read data HTTPS; application tokenDataflow Order15ccd509-98eb-49ad-b9c2-b4a2926d17800Out Of Scope71f3d9aa-b8ef-4e54-8126-607a1d903103falseReason For Out Of Scope752473b6-52d4-4776-9a24-202153f7d579Predefined Static AttributesDestination AuthenticatedauthenticatesDestinationYes0Provides ConfidentialityprovidesConfidentialityYes0Provides IntegrityprovidesIntegrityYes0Configurable AttributesAs Generic Data FlowPhysical NetworkchannelNot SelectedWireWi-FiBluetooth2G-4G0Source AuthenticatedauthenticatesSourceNot SelectedNoYes0Transmits XMLXMLencNoYes0Contains CookiesCookiesYesNo0SOAP PayloadSOAPNoYes0REST PayloadRESTNoYes0RSS PayloadRSSNoYes0JSON PayloadJSONNoYes0Forgery Protection54851a3b-65da-4902-b4e0-94ef015be735Not SelectedValidateAntiForgeryTokenAttributeViewStateUserKeyNonceOther dynamic canaryStatic header not available to the browserOtherNoneNot applicable because the request does not change data0SE.DF.TMCore.HTTPS443470SouthSouth6480d8e0-a4f9-4cc4-90ab-d5ab2a4d4e762904862f23a6eb-aa7a-425c-9d2f-07a6d7ef6a1864355728ded6cf-6aad-4a36-a207-6cae85e1746eGE.DF28ded6cf-6aad-4a36-a207-6cae85e1746eHTTPSName4. Get secrets +HTTPS; Managed identity +[SM]Dataflow Order15ccd509-98eb-49ad-b9c2-b4a2926d17800Out Of Scope71f3d9aa-b8ef-4e54-8126-607a1d903103falseReason For Out Of Scope752473b6-52d4-4776-9a24-202153f7d579Predefined Static AttributesDestination AuthenticatedauthenticatesDestinationYes0Provides ConfidentialityprovidesConfidentialityYes0Provides IntegrityprovidesIntegrityYes0Configurable AttributesAs Generic Data FlowPhysical NetworkchannelNot SelectedWireWi-FiBluetooth2G-4G0Source AuthenticatedauthenticatesSourceNot SelectedNoYes0Transmits XMLXMLencNoYes0Contains CookiesCookiesYesNo0SOAP PayloadSOAPNoYes0REST PayloadRESTNoYes0RSS PayloadRSSNoYes0JSON PayloadJSONNoYes0Forgery Protection54851a3b-65da-4902-b4e0-94ef015be735Not SelectedValidateAntiForgeryTokenAttributeViewStateUserKeyNonceOther dynamic canaryStatic header not available to the browserOtherNoneNot applicable because the request does not change data0SE.DF.TMCore.HTTPS645104NoneSouth00000000-0000-0000-0000-00000000000065026163a3b273-2c3b-40ef-bc41-ae67e941c8bd7521051
DRAWINGSURFACEf7b3d20a-64c9-438b-8f60-a1703c181bbaDiagramNameDiagram 2DRAWINGSURFACE
Diagram 2
1
E56480d8e0-a4f9-4cc4-90ab-d5ab2a4d4e763b63b270-d39a-4d5f-9df4-33665a91d32b78cb7043-4910-4f9e-8544-e7b2153dff3e418b6a60-9f3a-42a7-9a39-8ef51ee8c0d23b63b270-d39a-4d5f-9df4-33665a91d32b206480d8e0-a4f9-4cc4-90ab-d5ab2a4d4e76:3b63b270-d39a-4d5f-9df4-33665a91d32b:78cb7043-4910-4f9e-8544-e7b2153dff3e0001-01-01T00:00:00HighTitleElevation Using ImpersonationUserThreatCategoryElevation Of PrivilegeUserThreatShortDescriptionA user subject gains increased capability or privilege by taking advantage of an implementation bug.UserThreatDescriptionService Bus may be able to impersonate the context of Azure Function in order to gain additional privilege.InteractionString12.Queue the message HTTPS; Managed Identity [SM]PriorityHigh6480d8e0-a4f9-4cc4-90ab-d5ab2a4d4e76AutoGenerated78cb7043-4910-4f9e-8544-e7b2153dff3eE5falsefalseE578cb7043-4910-4f9e-8544-e7b2153dff3e273c0d07-97af-4fa8-8a6d-756d72076e196480d8e0-a4f9-4cc4-90ab-d5ab2a4d4e76418b6a60-9f3a-42a7-9a39-8ef51ee8c0d2273c0d07-97af-4fa8-8a6d-756d72076e191978cb7043-4910-4f9e-8544-e7b2153dff3e:273c0d07-97af-4fa8-8a6d-756d72076e19:6480d8e0-a4f9-4cc4-90ab-d5ab2a4d4e760001-01-01T00:00:00HighTitleElevation Using ImpersonationUserThreatCategoryElevation Of PrivilegeUserThreatShortDescriptionA user subject gains increased capability or privilege by taking advantage of an implementation bug.UserThreatDescriptionAzure Function may be able to impersonate the context of Service Bus in order to gain additional privilege.InteractionString8. App Trigger over HTTPSPriorityHigh78cb7043-4910-4f9e-8544-e7b2153dff3eAutoGenerated6480d8e0-a4f9-4cc4-90ab-d5ab2a4d4e76E5falsefalseE56480d8e0-a4f9-4cc4-90ab-d5ab2a4d4e76433a9d8a-84b0-4846-a972-5394dffe35292f23a6eb-aa7a-425c-9d2f-07a6d7ef6a18418b6a60-9f3a-42a7-9a39-8ef51ee8c0d2433a9d8a-84b0-4846-a972-5394dffe3529226480d8e0-a4f9-4cc4-90ab-d5ab2a4d4e76:433a9d8a-84b0-4846-a972-5394dffe3529:2f23a6eb-aa7a-425c-9d2f-07a6d7ef6a180001-01-01T00:00:00HighTitleElevation Using ImpersonationUserThreatCategoryElevation Of PrivilegeUserThreatShortDescriptionA user subject gains increased capability or privilege by taking advantage of an implementation bug.UserThreatDescriptionMicrosoft Graph may be able to impersonate the context of Azure Function in order to gain additional privilege.InteractionString9.Read data HTTPS; application tokenPriorityHigh6480d8e0-a4f9-4cc4-90ab-d5ab2a4d4e76AutoGenerated2f23a6eb-aa7a-425c-9d2f-07a6d7ef6a18E5falsefalseT26480d8e0-a4f9-4cc4-90ab-d5ab2a4d4e76433a9d8a-84b0-4846-a972-5394dffe35292f23a6eb-aa7a-425c-9d2f-07a6d7ef6a18418b6a60-9f3a-42a7-9a39-8ef51ee8c0d2433a9d8a-84b0-4846-a972-5394dffe3529216480d8e0-a4f9-4cc4-90ab-d5ab2a4d4e76:433a9d8a-84b0-4846-a972-5394dffe3529:2f23a6eb-aa7a-425c-9d2f-07a6d7ef6a180001-01-01T00:00:00HighTitleAzure Function Process Memory TamperedUserThreatCategoryTamperingUserThreatShortDescriptionTampering 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 processes.UserThreatDescriptionIf Azure Function is given access to memory, such as shared memory or pointers, or is given the ability to control what Microsoft Graph executes (for example, passing back a function pointer.), then Azure Function can tamper with Microsoft Graph. Consider if the function could work with less access to memory, such as passing data rather than pointers. Copy in data provided, and then validate it.InteractionString9.Read data HTTPS; application tokenPriorityHigh6480d8e0-a4f9-4cc4-90ab-d5ab2a4d4e76AutoGenerated2f23a6eb-aa7a-425c-9d2f-07a6d7ef6a18T2falsefalseT278cb7043-4910-4f9e-8544-e7b2153dff3e273c0d07-97af-4fa8-8a6d-756d72076e196480d8e0-a4f9-4cc4-90ab-d5ab2a4d4e76418b6a60-9f3a-42a7-9a39-8ef51ee8c0d2273c0d07-97af-4fa8-8a6d-756d72076e191878cb7043-4910-4f9e-8544-e7b2153dff3e:273c0d07-97af-4fa8-8a6d-756d72076e19:6480d8e0-a4f9-4cc4-90ab-d5ab2a4d4e760001-01-01T00:00:00HighTitleService Bus Process Memory TamperedUserThreatCategoryTamperingUserThreatShortDescriptionTampering 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 processes.UserThreatDescriptionIf Service Bus is given access to memory, such as shared memory or pointers, or is given the ability to control what Azure Function executes (for example, passing back a function pointer.), then Service Bus can tamper with Azure Function. Consider if the function could work with less access to memory, such as passing data rather than pointers. Copy in data provided, and then validate it.InteractionString8. App Trigger over HTTPSPriorityHigh78cb7043-4910-4f9e-8544-e7b2153dff3eAutoGenerated6480d8e0-a4f9-4cc4-90ab-d5ab2a4d4e76T2falsefalseE505fec340-05db-4922-946d-112ff7373c03d692dfd7-b8cf-4757-9753-6ac27d34e69d78cb7043-4910-4f9e-8544-e7b2153dff3e418b6a60-9f3a-42a7-9a39-8ef51ee8c0d2d692dfd7-b8cf-4757-9753-6ac27d34e69d1705fec340-05db-4922-946d-112ff7373c03:d692dfd7-b8cf-4757-9753-6ac27d34e69d:78cb7043-4910-4f9e-8544-e7b2153dff3e0001-01-01T00:00:00HighTitleElevation Using ImpersonationUserThreatCategoryElevation Of PrivilegeUserThreatShortDescriptionA user subject gains increased capability or privilege by taking advantage of an implementation bug.UserThreatDescriptionService Bus may be able to impersonate the context of Company Communicator in order to gain additional privilege.InteractionString7. Queue the message HTTPS; Managed Identity[SM]PriorityHigh05fec340-05db-4922-946d-112ff7373c03AutoGenerated78cb7043-4910-4f9e-8544-e7b2153dff3eE5falsefalseD205fec340-05db-4922-946d-112ff7373c035c421ce7-b8d7-42c2-89e0-8eebc61fc6bbd8fe453f-286e-4fec-b7c1-33c9a1e56d4c418b6a60-9f3a-42a7-9a39-8ef51ee8c0d25c421ce7-b8d7-42c2-89e0-8eebc61fc6bb1105fec340-05db-4922-946d-112ff7373c03:5c421ce7-b8d7-42c2-89e0-8eebc61fc6bb:d8fe453f-286e-4fec-b7c1-33c9a1e56d4c0001-01-01T00:00:00HighTitlePotential Excessive Resource Consumption for Company Communicator or Application InsightsUserThreatCategoryDenial Of ServiceUserThreatShortDescriptionDenial of Service happens when the process or a datastore is not able to service incoming requests or perform up to spec.UserThreatDescriptionDoes Company Communicator or Application Insights take explicit steps to control resource consumption? Resource consumption attacks can be hard to deal with, and there are times that it makes sense to let the OS do the job. Be careful that your resource requests don't deadlock, and that they do timeout.InteractionString13. Log telemetry HTTPS; API key [EUPI, SM]PriorityHigh05fec340-05db-4922-946d-112ff7373c03AutoGeneratedd8fe453f-286e-4fec-b7c1-33c9a1e56d4cD2falsefalseS7.105fec340-05db-4922-946d-112ff7373c035c421ce7-b8d7-42c2-89e0-8eebc61fc6bbd8fe453f-286e-4fec-b7c1-33c9a1e56d4c418b6a60-9f3a-42a7-9a39-8ef51ee8c0d25c421ce7-b8d7-42c2-89e0-8eebc61fc6bb1005fec340-05db-4922-946d-112ff7373c03:5c421ce7-b8d7-42c2-89e0-8eebc61fc6bb:d8fe453f-286e-4fec-b7c1-33c9a1e56d4c0001-01-01T00:00:00HighTitleSpoofing of Destination Data Store Application InsightsUserThreatCategorySpoofingUserThreatShortDescriptionSpoofing is when a process or entity is something other than its claimed identity. Examples include substituting a process, a file, website or a network address.UserThreatDescriptionApplication Insights may be spoofed by an attacker and this may lead to data being written to the attacker's target instead of Application Insights. Consider using a standard authentication mechanism to identify the destination data store.InteractionString13. Log telemetry HTTPS; API key [EUPI, SM]PriorityHigh05fec340-05db-4922-946d-112ff7373c03AutoGeneratedd8fe453f-286e-4fec-b7c1-33c9a1e56d4cS7.1falsefalseT205fec340-05db-4922-946d-112ff7373c03059e20ab-f3df-4db4-94d7-e3c0fd81d9052f23a6eb-aa7a-425c-9d2f-07a6d7ef6a18418b6a60-9f3a-42a7-9a39-8ef51ee8c0d2059e20ab-f3df-4db4-94d7-e3c0fd81d905805fec340-05db-4922-946d-112ff7373c03:059e20ab-f3df-4db4-94d7-e3c0fd81d905:2f23a6eb-aa7a-425c-9d2f-07a6d7ef6a180001-01-01T00:00:00HighTitleCompany Communicator Process Memory TamperedUserThreatCategoryTamperingUserThreatShortDescriptionTampering 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 processes.UserThreatDescriptionIf Company Communicator is given access to memory, such as shared memory or pointers, or is given the ability to control what Microsoft Graph executes (for example, passing back a function pointer.), then Company Communicator can tamper with Microsoft Graph. Consider if the function could work with less access to memory, such as passing data rather than pointers. Copy in data provided, and then validate it.InteractionString6.Read data HTTPS; delegated tokenPriorityHigh05fec340-05db-4922-946d-112ff7373c03AutoGenerated2f23a6eb-aa7a-425c-9d2f-07a6d7ef6a18T2falsefalseE505fec340-05db-4922-946d-112ff7373c03059e20ab-f3df-4db4-94d7-e3c0fd81d9052f23a6eb-aa7a-425c-9d2f-07a6d7ef6a18418b6a60-9f3a-42a7-9a39-8ef51ee8c0d2059e20ab-f3df-4db4-94d7-e3c0fd81d905905fec340-05db-4922-946d-112ff7373c03:059e20ab-f3df-4db4-94d7-e3c0fd81d905:2f23a6eb-aa7a-425c-9d2f-07a6d7ef6a180001-01-01T00:00:00HighTitleElevation Using ImpersonationUserThreatCategoryElevation Of PrivilegeUserThreatShortDescriptionA user subject gains increased capability or privilege by taking advantage of an implementation bug.UserThreatDescriptionMicrosoft Graph may be able to impersonate the context of Company Communicator in order to gain additional privilege.InteractionString6.Read data HTTPS; delegated tokenPriorityHigh05fec340-05db-4922-946d-112ff7373c03AutoGenerated2f23a6eb-aa7a-425c-9d2f-07a6d7ef6a18E5falsefalseS7.105fec340-05db-4922-946d-112ff7373c03d3145983-ea29-4e12-8ba6-24b6792eb8f6f39b41ff-538a-4f04-b911-ba7a2fe73fa2418b6a60-9f3a-42a7-9a39-8ef51ee8c0d2d3145983-ea29-4e12-8ba6-24b6792eb8f61205fec340-05db-4922-946d-112ff7373c03:d3145983-ea29-4e12-8ba6-24b6792eb8f6:f39b41ff-538a-4f04-b911-ba7a2fe73fa20001-01-01T00:00:00HighTitleSpoofing of Destination Data Store Azure Table StorageUserThreatCategorySpoofingUserThreatShortDescriptionSpoofing is when a process or entity is something other than its claimed identity. Examples include substituting a process, a file, website or a network address.UserThreatDescriptionAzure Table Storage may be spoofed by an attacker and this may lead to data being written to the attacker's target instead of Azure Table Storage. Consider using a standard authentication mechanism to identify the destination data store.InteractionString5. Read/update data HTTPS; connection string [CC, EUII, EUPIPriorityHigh05fec340-05db-4922-946d-112ff7373c03AutoGeneratedf39b41ff-538a-4f04-b911-ba7a2fe73fa2S7.1falsefalseD205fec340-05db-4922-946d-112ff7373c03d3145983-ea29-4e12-8ba6-24b6792eb8f6f39b41ff-538a-4f04-b911-ba7a2fe73fa2418b6a60-9f3a-42a7-9a39-8ef51ee8c0d2d3145983-ea29-4e12-8ba6-24b6792eb8f61305fec340-05db-4922-946d-112ff7373c03:d3145983-ea29-4e12-8ba6-24b6792eb8f6:f39b41ff-538a-4f04-b911-ba7a2fe73fa20001-01-01T00:00:00HighTitlePotential Excessive Resource Consumption for Company Communicator or Azure Table StorageUserThreatCategoryDenial Of ServiceUserThreatShortDescriptionDenial of Service happens when the process or a datastore is not able to service incoming requests or perform up to spec.UserThreatDescriptionDoes Company Communicator or Azure Table Storage take explicit steps to control resource consumption? Resource consumption attacks can be hard to deal with, and there are times that it makes sense to let the OS do the job. Be careful that your resource requests don't deadlock, and that they do timeout.InteractionString5. Read/update data HTTPS; connection string [CC, EUII, EUPIPriorityHigh05fec340-05db-4922-946d-112ff7373c03AutoGeneratedf39b41ff-538a-4f04-b911-ba7a2fe73fa2D2falsefalseS7.16480d8e0-a4f9-4cc4-90ab-d5ab2a4d4e76c47fbb19-55fe-45a0-883a-1dcb4f3e12b4f39b41ff-538a-4f04-b911-ba7a2fe73fa2418b6a60-9f3a-42a7-9a39-8ef51ee8c0d2c47fbb19-55fe-45a0-883a-1dcb4f3e12b4146480d8e0-a4f9-4cc4-90ab-d5ab2a4d4e76:c47fbb19-55fe-45a0-883a-1dcb4f3e12b4:f39b41ff-538a-4f04-b911-ba7a2fe73fa20001-01-01T00:00:00HighTitleSpoofing of Destination Data Store Azure Table StorageUserThreatCategorySpoofingUserThreatShortDescriptionSpoofing is when a process or entity is something other than its claimed identity. Examples include substituting a process, a file, website or a network address.UserThreatDescriptionAzure Table Storage may be spoofed by an attacker and this may lead to data being written to the attacker's target instead of Azure Table Storage. Consider using a standard authentication mechanism to identify the destination data store.InteractionString10. Read/update data HTTPS; connection string [CC, EUII, EUPIPriorityHigh6480d8e0-a4f9-4cc4-90ab-d5ab2a4d4e76AutoGeneratedf39b41ff-538a-4f04-b911-ba7a2fe73fa2S7.1falsefalseD26480d8e0-a4f9-4cc4-90ab-d5ab2a4d4e76c47fbb19-55fe-45a0-883a-1dcb4f3e12b4f39b41ff-538a-4f04-b911-ba7a2fe73fa2418b6a60-9f3a-42a7-9a39-8ef51ee8c0d2c47fbb19-55fe-45a0-883a-1dcb4f3e12b4156480d8e0-a4f9-4cc4-90ab-d5ab2a4d4e76:c47fbb19-55fe-45a0-883a-1dcb4f3e12b4:f39b41ff-538a-4f04-b911-ba7a2fe73fa20001-01-01T00:00:00HighTitlePotential Excessive Resource Consumption for Azure Function or Azure Table StorageUserThreatCategoryDenial Of ServiceUserThreatShortDescriptionDenial of Service happens when the process or a datastore is not able to service incoming requests or perform up to spec.UserThreatDescriptionDoes Azure Function or Azure Table Storage take explicit steps to control resource consumption? Resource consumption attacks can be hard to deal with, and there are times that it makes sense to let the OS do the job. Be careful that your resource requests don't deadlock, and that they do timeout.InteractionString10. Read/update data HTTPS; connection string [CC, EUII, EUPIPriorityHigh6480d8e0-a4f9-4cc4-90ab-d5ab2a4d4e76AutoGeneratedf39b41ff-538a-4f04-b911-ba7a2fe73fa2D2falsefalsetrue4.3falsefalseNot SelectedManagedUnmanagedCode TypeVirtualDynamiccodeTypeListfalseNot SelectedKernelSystemNetwork ServiceLocal ServiceAdministratorStandard User With ElevationStandard User Without ElevationWindows Store AppRunning AsVirtualDynamicrunningAsListfalseNot SelectedAppContainerLow Integrity LevelMicrosoft Office Isolated Conversion Environment (MOICE)SandboxIsolation LevelVirtualDynamicIsolationListfalseNot SelectedAny Remote User or EntityKernel, System, or Local AdminLocal or Network ServiceLocal Standard User With ElevationLocal Standard User Without ElevationWindows Store Apps or App Container ProcessesNothingOtherAccepts Input FromVirtualDynamicacceptsInputFromListfalseNoYesImplements or Uses an Authentication MechanismVirtualDynamicimplementsAuthenticationSchemeListfalseNoYesImplements or Uses an Authorization MechanismVirtualDynamicimplementsCustomAuthorizationMechanismListfalseNoYesImplements or Uses a Communication ProtocolVirtualDynamicimplementsCommunicationProtocolListfalseNot SelectedYesNoSanitizes InputVirtualDynamichasInputSanitizersListfalseNot SelectedYesNoSanitizes OutputVirtualDynamichasOutputSanitizersListA representation of a generic process.falseGE.PCentered on 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Generic ProcessROOTEllipsefalseAnyAnyfalsefalseNot ApplicableNoYesAuthenticates ItselfVirtualDynamicauthenticatesItselfListfalseNot SelectedCodeHumanTypeVirtualDynamictypeListfalseNoYesMicrosoftVirtualDynamicMSList + A representation of an external interactor. + falseGE.EILower right of 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Generic External InteractorROOTRectanglefalseAnyAnyfalsefalseNoYesStores CredentialsVirtualDynamicstoresCredentialsListfalseNoYesStores Log DataVirtualDynamicstoresLogDataListfalseNoYesEncryptedVirtualDynamicEncryptedListfalseNoYesSignedVirtualDynamicSignedListfalseNoYesWrite AccessVirtualDynamicAccessTypeListfalseNoYesRemovable StorageVirtualDynamicRemoveableStorageListfalseNoYesBackupVirtualDynamicBackupListfalseNoYesSharedVirtualDynamicsharedListfalseSQL Relational DatabaseNon Relational DatabaseFile SystemRegistryConfigurationCacheHTML5 StorageCookieDeviceStore TypeVirtualDynamicstoreTypeList + A representation of a data store. + falseGE.DSLower right of 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 Data StoreROOTParallelLinesfalseAnyAnyfalsefalseNot SelectedWireWi-FiBluetooth2G-4GPhysical NetworkVirtualDynamicchannelListfalseNot SelectedNoYesSource AuthenticatedVirtualDynamicauthenticatesSourceListfalseNoYesDestination AuthenticatedVirtualDynamicauthenticatesDestinationListfalseNoYesProvides ConfidentialityVirtualDynamicprovidesConfidentialityListfalseNoYesProvides IntegrityVirtualDynamicprovidesIntegrityListfalseNoYesTransmits XMLVirtualDynamicXMLencListfalseYesNoContains CookiesVirtualDynamicCookiesListfalseNoYesSOAP PayloadVirtualDynamicSOAPListfalseNoYesREST PayloadVirtualDynamicRESTListfalseNoYesRSS PayloadVirtualDynamicRSSListfalseNoYesJSON PayloadVirtualDynamicJSONListfalseNot SelectedValidateAntiForgeryTokenAttributeViewStateUserKeyNonceOther dynamic canaryStatic header not available to the browserOtherNoneNot applicable because the request does not change dataForgery ProtectionVirtualDynamic54851a3b-65da-4902-b4e0-94ef015be735List + A unidirectional representation of the flow of data between elements. + falseGE.DFBefore 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Generic Data FlowROOTLinefalseAnyAnyfalse + An arc representation of a trust boundary. + falseGE.TB.LBefore labeliVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAZdEVYdFNvZnR3YXJlAEFkb2JlIEltYWdlUmVhZHlxyWU8AAABX0lEQVQ4T2NgNPXGh/mhGJscGCNzQArtgVgfxmcy87kAwlA5ZLVwDGOAFQPp/1Dcj8zHZwiY4LUPdgLSMM0YmM8+5JaAY5gRkI3dAJuUUlsgjVUzCM/ZuDPg////vEA2dgNAkqpBKTuBbKwGRNV0iQNpmCZQGMG9AxPk57IJvA6ksRrAYu67EEjLA7E+s7nPReQwAWtGC0CiMMwQkPNZ5H0TtqArIIRBAWueUCgM9gLQEG1QGHDbBr1YuftQDJDvapFYtAhdEwwDY+TO8cvXXUCWw8IAbMjCrXtDgDQHlK8E04CO1YPTVoA0A9nwQIQZAtYMxaBAw2oAFINSLaoBSFgfGEgPgDQ2jWAs5hZVCaSxGwB0Ca+iX9I2IBusGORn3YistTA+q4Xf59KJcy1BarEaAMJAQ8ABixRg6omN/fWgwF26Y38EzLsghfiwNhBbADELlC8KxEpAzAHh/2cAANCSU7ngF2KpAAAAAElFTkSuQmCCGeneric Trust Line BoundaryROOTLineBoundaryfalseAnyAnyfalse + A border representation of a trust boundary. + falseGE.TB.BBefore labeliVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAOxAAADsQBlSsOGwAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAABGSURBVDhPY/hPIWBQ9Ev6z2jqDccPnr0ESxArzoDMAeEDZy+DFRIrDjeAVDCcDIDyyQajgTioAhGEQekdHx+bGIUGeP8HAJ4fIfJijo6MAAAAAElFTkSuQmCCGeneric Trust Border BoundaryROOTBorderBoundaryfalseAnyAnyfalse + A representation of an annotation. + falseGE.AFree Text AnnotationROOTAnnotationfalseAnyAnyTwC MSECcc62ebae-3748-431e-b1df-f4220dc9003fSDL TM Knowledge Base (Core)4.1.0.11false + A Windows Process. + falseSE.P.TMCore.OSProcessCentered on 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 ProcessGE.PInheritedfalseAnyAnyfalse + A thread of execution in a Windows process. + falseSE.P.TMCore.ThreadCentered on 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.PInheritedfalseAnyAnyfalsefalseUnmanagedCode TypeVirtualStaticcodeTypeList + A thread of execution in the Windows kernel. + falseSE.P.TMCore.KernelThreadCentered on stenciliVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGOfPtRkwAAACBjSFJNAACHDwAAjA8AAP1SAACBQAAAfXkAAOmLAAA85QAAGcxzPIV3AAAKOWlDQ1BQaG90b3Nob3AgSUNDIHByb2ZpbGUAAEjHnZZ3VFTXFofPvXd6oc0wAlKG3rvAANJ7k15FYZgZYCgDDjM0sSGiAhFFRJoiSFDEgNFQJFZEsRAUVLAHJAgoMRhFVCxvRtaLrqy89/Ly++Osb+2z97n77L3PWhcAkqcvl5cGSwGQyhPwgzyc6RGRUXTsAIABHmCAKQBMVka6X7B7CBDJy82FniFyAl8EAfB6WLwCcNPQM4BOB/+fpFnpfIHomAARm7M5GSwRF4g4JUuQLrbPipgalyxmGCVmvihBEcuJOWGRDT77LLKjmNmpPLaIxTmns1PZYu4V8bZMIUfEiK+ICzO5nCwR3xKxRoowlSviN+LYVA4zAwAUSWwXcFiJIjYRMYkfEuQi4uUA4EgJX3HcVyzgZAvEl3JJS8/hcxMSBXQdli7d1NqaQffkZKVwBALDACYrmcln013SUtOZvBwAFu/8WTLi2tJFRbY0tba0NDQzMv2qUP91829K3NtFehn4uWcQrf+L7a/80hoAYMyJarPziy2uCoDOLQDI3fti0zgAgKSobx3Xv7oPTTwviQJBuo2xcVZWlhGXwzISF/QP/U+Hv6GvvmckPu6P8tBdOfFMYYqALq4bKy0lTcinZ6QzWRy64Z+H+B8H/nUeBkGceA6fwxNFhImmjMtLELWbx+YKuGk8Opf3n5r4D8P+pMW5FonS+BFQY4yA1HUqQH7tBygKESDR+8Vd/6NvvvgwIH554SqTi3P/7zf9Z8Gl4iWDm/A5ziUohM4S8jMX98TPEqABAUgCKpAHykAd6ABDYAasgC1wBG7AG/iDEBAJVgMWSASpgA+yQB7YBApBMdgJ9oBqUAcaQTNoBcdBJzgFzoNL4Bq4AW6D+2AUTIBnYBa8BgsQBGEhMkSB5CEVSBPSh8wgBmQPuUG+UBAUCcVCCRAPEkJ50GaoGCqDqqF6qBn6HjoJnYeuQIPQXWgMmoZ+h97BCEyCqbASrAUbwwzYCfaBQ+BVcAK8Bs6FC+AdcCXcAB+FO+Dz8DX4NjwKP4PnEIAQERqiihgiDMQF8UeikHiEj6xHipAKpAFpRbqRPuQmMorMIG9RGBQFRUcZomxRnqhQFAu1BrUeVYKqRh1GdaB6UTdRY6hZ1Ec0Ga2I1kfboL3QEegEdBa6EF2BbkK3oy+ib6Mn0K8xGAwNo42xwnhiIjFJmLWYEsw+TBvmHGYQM46Zw2Kx8lh9rB3WH8vECrCF2CrsUexZ7BB2AvsGR8Sp4Mxw7rgoHA+Xj6vAHcGdwQ3hJnELeCm8Jt4G749n43PwpfhGfDf+On4Cv0CQJmgT7AghhCTCJkIloZVwkfCA8JJIJKoRrYmBRC5xI7GSeIx4mThGfEuSIemRXEjRJCFpB+kQ6RzpLuklmUzWIjuSo8gC8g5yM/kC+RH5jQRFwkjCS4ItsUGiRqJDYkjiuSReUlPSSXK1ZK5kheQJyeuSM1J4KS0pFymm1HqpGqmTUiNSc9IUaVNpf+lU6RLpI9JXpKdksDJaMm4ybJkCmYMyF2TGKQhFneJCYVE2UxopFykTVAxVm+pFTaIWU7+jDlBnZWVkl8mGyWbL1sielh2lITQtmhcthVZKO04bpr1borTEaQlnyfYlrUuGlszLLZVzlOPIFcm1yd2WeydPl3eTT5bfJd8p/1ABpaCnEKiQpbBf4aLCzFLqUtulrKVFS48vvacIK+opBimuVTyo2K84p6Ss5KGUrlSldEFpRpmm7KicpFyufEZ5WoWiYq/CVSlXOavylC5Ld6Kn0CvpvfRZVUVVT1Whar3qgOqCmrZaqFq+WpvaQ3WCOkM9Xr1cvUd9VkNFw08jT6NF454mXpOhmai5V7NPc15LWytca6tWp9aUtpy2l3audov2Ax2yjoPOGp0GnVu6GF2GbrLuPt0berCehV6iXo3edX1Y31Kfq79Pf9AAbWBtwDNoMBgxJBk6GWYathiOGdGMfI3yjTqNnhtrGEcZ7zLuM/5oYmGSYtJoct9UxtTbNN+02/R3Mz0zllmN2S1zsrm7+QbzLvMXy/SXcZbtX3bHgmLhZ7HVosfig6WVJd+y1XLaSsMq1qrWaoRBZQQwShiXrdHWztYbrE9Zv7WxtBHYHLf5zdbQNtn2iO3Ucu3lnOWNy8ft1OyYdvV2o/Z0+1j7A/ajDqoOTIcGh8eO6o5sxybHSSddpySno07PnU2c+c7tzvMuNi7rXM65Iq4erkWuA24ybqFu1W6P3NXcE9xb3Gc9LDzWepzzRHv6eO7yHPFS8mJ5NXvNelt5r/Pu9SH5BPtU+zz21fPl+3b7wX7efrv9HqzQXMFb0ekP/L38d/s/DNAOWBPwYyAmMCCwJvBJkGlQXlBfMCU4JvhI8OsQ55DSkPuhOqHC0J4wybDosOaw+XDX8LLw0QjjiHUR1yIVIrmRXVHYqLCopqi5lW4r96yciLaILoweXqW9KnvVldUKq1NWn46RjGHGnIhFx4bHHol9z/RnNjDn4rziauNmWS6svaxnbEd2OXuaY8cp40zG28WXxU8l2CXsTphOdEisSJzhunCruS+SPJPqkuaT/ZMPJX9KCU9pS8Wlxqae5Mnwknm9acpp2WmD6frphemja2zW7Fkzy/fhN2VAGasyugRU0c9Uv1BHuEU4lmmfWZP5Jiss60S2dDYvuz9HL2d7zmSue+63a1FrWWt78lTzNuWNrXNaV78eWh+3vmeD+oaCDRMbPTYe3kTYlLzpp3yT/LL8V5vDN3cXKBVsLBjf4rGlpVCikF84stV2a9021DbutoHt5turtn8sYhddLTYprih+X8IqufqN6TeV33zaEb9joNSydP9OzE7ezuFdDrsOl0mX5ZaN7/bb3VFOLy8qf7UnZs+VimUVdXsJe4V7Ryt9K7uqNKp2Vr2vTqy+XeNc01arWLu9dn4fe9/Qfsf9rXVKdcV17w5wD9yp96jvaNBqqDiIOZh58EljWGPft4xvm5sUmoqbPhziHRo9HHS4t9mqufmI4pHSFrhF2DJ9NProje9cv+tqNWytb6O1FR8Dx4THnn4f+/3wcZ/jPScYJ1p/0Pyhtp3SXtQBdeR0zHYmdo52RXYNnvQ+2dNt293+o9GPh06pnqo5LXu69AzhTMGZT2dzz86dSz83cz7h/HhPTM/9CxEXbvUG9g5c9Ll4+ZL7pQt9Tn1nL9tdPnXF5srJq4yrndcsr3X0W/S3/2TxU/uA5UDHdavrXTesb3QPLh88M+QwdP6m681Lt7xuXbu94vbgcOjwnZHokdE77DtTd1PuvriXeW/h/sYH6AdFD6UeVjxSfNTws+7PbaOWo6fHXMf6Hwc/vj/OGn/2S8Yv7ycKnpCfVEyqTDZPmU2dmnafvvF05dOJZ+nPFmYKf5X+tfa5zvMffnP8rX82YnbiBf/Fp99LXsq/PPRq2aueuYC5R69TXy/MF72Rf3P4LeNt37vwd5MLWe+x7ys/6H7o/ujz8cGn1E+f/gUDmPP8usTo0wAAAAlwSFlzAAAOxAAADsQBlSsOGwAAAEFJREFUOE9jYDT1ngnE/8nEM0EG/EETJAV/ABmATYJYTD0DQDQ5eNSAUQNAmDoGgDITugSxGGzAfCAGuYIM7D0HAH9a5DRx46KEAAAAAElFTkSuQmCCKernel ThreadGE.PInheritedfalseAnyAnyfalsefalseUnmanagedCode TypeVirtualStaticcodeTypeList + A representation of a Win32 or Win64 application. + falseSE.P.TMCore.WinAppCentered on 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 ApplicationGE.PInheritedfalseAnyAnyfalsefalseManagedCode TypeVirtualStaticcodeTypeList + A representation of a .NET Web application. + falseSE.P.TMCore.NetAppCentered on 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 ApplicationGE.PInheritedfalseAnyAnyfalsefalseUnmanagedCode TypeVirtualStaticcodeTypeList + A representation of a thick client. + falseSE.P.TMCore.ThickClientCentered on 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Thick ClientGE.PInheritedfalseAnyAnyfalsefalseUnmanagedCode TypeVirtualStaticcodeTypeList + A representation of a browser client. + falseSE.P.TMCore.BrowserClientCentered on stenciliVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGOfPtRkwAAACBjSFJNAACHDwAAjA8AAP1SAACBQAAAfXkAAOmLAAA85QAAGcxzPIV3AAAKOWlDQ1BQaG90b3Nob3AgSUNDIHByb2ZpbGUAAEjHnZZ3VFTXFofPvXd6oc0wAlKG3rvAANJ7k15FYZgZYCgDDjM0sSGiAhFFRJoiSFDEgNFQJFZEsRAUVLAHJAgoMRhFVCxvRtaLrqy89/Ly++Osb+2z97n77L3PWhcAkqcvl5cGSwGQyhPwgzyc6RGRUXTsAIABHmCAKQBMVka6X7B7CBDJy82FniFyAl8EAfB6WLwCcNPQM4BOB/+fpFnpfIHomAARm7M5GSwRF4g4JUuQLrbPipgalyxmGCVmvihBEcuJOWGRDT77LLKjmNmpPLaIxTmns1PZYu4V8bZMIUfEiK+ICzO5nCwR3xKxRoowlSviN+LYVA4zAwAUSWwXcFiJIjYRMYkfEuQi4uUA4EgJX3HcVyzgZAvEl3JJS8/hcxMSBXQdli7d1NqaQffkZKVwBALDACYrmcln013SUtOZvBwAFu/8WTLi2tJFRbY0tba0NDQzMv2qUP91829K3NtFehn4uWcQrf+L7a/80hoAYMyJarPziy2uCoDOLQDI3fti0zgAgKSobx3Xv7oPTTwviQJBuo2xcVZWlhGXwzISF/QP/U+Hv6GvvmckPu6P8tBdOfFMYYqALq4bKy0lTcinZ6QzWRy64Z+H+B8H/nUeBkGceA6fwxNFhImmjMtLELWbx+YKuGk8Opf3n5r4D8P+pMW5FonS+BFQY4yA1HUqQH7tBygKESDR+8Vd/6NvvvgwIH554SqTi3P/7zf9Z8Gl4iWDm/A5ziUohM4S8jMX98TPEqABAUgCKpAHykAd6ABDYAasgC1wBG7AG/iDEBAJVgMWSASpgA+yQB7YBApBMdgJ9oBqUAcaQTNoBcdBJzgFzoNL4Bq4AW6D+2AUTIBnYBa8BgsQBGEhMkSB5CEVSBPSh8wgBmQPuUG+UBAUCcVCCRAPEkJ50GaoGCqDqqF6qBn6HjoJnYeuQIPQXWgMmoZ+h97BCEyCqbASrAUbwwzYCfaBQ+BVcAK8Bs6FC+AdcCXcAB+FO+Dz8DX4NjwKP4PnEIAQERqiihgiDMQF8UeikHiEj6xHipAKpAFpRbqRPuQmMorMIG9RGBQFRUcZomxRnqhQFAu1BrUeVYKqRh1GdaB6UTdRY6hZ1Ec0Ga2I1kfboL3QEegEdBa6EF2BbkK3oy+ib6Mn0K8xGAwNo42xwnhiIjFJmLWYEsw+TBvmHGYQM46Zw2Kx8lh9rB3WH8vECrCF2CrsUexZ7BB2AvsGR8Sp4Mxw7rgoHA+Xj6vAHcGdwQ3hJnELeCm8Jt4G749n43PwpfhGfDf+On4Cv0CQJmgT7AghhCTCJkIloZVwkfCA8JJIJKoRrYmBRC5xI7GSeIx4mThGfEuSIemRXEjRJCFpB+kQ6RzpLuklmUzWIjuSo8gC8g5yM/kC+RH5jQRFwkjCS4ItsUGiRqJDYkjiuSReUlPSSXK1ZK5kheQJyeuSM1J4KS0pFymm1HqpGqmTUiNSc9IUaVNpf+lU6RLpI9JXpKdksDJaMm4ybJkCmYMyF2TGKQhFneJCYVE2UxopFykTVAxVm+pFTaIWU7+jDlBnZWVkl8mGyWbL1sielh2lITQtmhcthVZKO04bpr1borTEaQlnyfYlrUuGlszLLZVzlOPIFcm1yd2WeydPl3eTT5bfJd8p/1ABpaCnEKiQpbBf4aLCzFLqUtulrKVFS48vvacIK+opBimuVTyo2K84p6Ss5KGUrlSldEFpRpmm7KicpFyufEZ5WoWiYq/CVSlXOavylC5Ld6Kn0CvpvfRZVUVVT1Whar3qgOqCmrZaqFq+WpvaQ3WCOkM9Xr1cvUd9VkNFw08jT6NF454mXpOhmai5V7NPc15LWytca6tWp9aUtpy2l3audov2Ax2yjoPOGp0GnVu6GF2GbrLuPt0berCehV6iXo3edX1Y31Kfq79Pf9AAbWBtwDNoMBgxJBk6GWYathiOGdGMfI3yjTqNnhtrGEcZ7zLuM/5oYmGSYtJoct9UxtTbNN+02/R3Mz0zllmN2S1zsrm7+QbzLvMXy/SXcZbtX3bHgmLhZ7HVosfig6WVJd+y1XLaSsMq1qrWaoRBZQQwShiXrdHWztYbrE9Zv7WxtBHYHLf5zdbQNtn2iO3Ucu3lnOWNy8ft1OyYdvV2o/Z0+1j7A/ajDqoOTIcGh8eO6o5sxybHSSddpySno07PnU2c+c7tzvMuNi7rXM65Iq4erkWuA24ybqFu1W6P3NXcE9xb3Gc9LDzWepzzRHv6eO7yHPFS8mJ5NXvNelt5r/Pu9SH5BPtU+zz21fPl+3b7wX7efrv9HqzQXMFb0ekP/L38d/s/DNAOWBPwYyAmMCCwJvBJkGlQXlBfMCU4JvhI8OsQ55DSkPuhOqHC0J4wybDosOaw+XDX8LLw0QjjiHUR1yIVIrmRXVHYqLCopqi5lW4r96yciLaILoweXqW9KnvVldUKq1NWn46RjGHGnIhFx4bHHol9z/RnNjDn4rziauNmWS6svaxnbEd2OXuaY8cp40zG28WXxU8l2CXsTphOdEisSJzhunCruS+SPJPqkuaT/ZMPJX9KCU9pS8Wlxqae5Mnwknm9acpp2WmD6frphemja2zW7Fkzy/fhN2VAGasyugRU0c9Uv1BHuEU4lmmfWZP5Jiss60S2dDYvuz9HL2d7zmSue+63a1FrWWt78lTzNuWNrXNaV78eWh+3vmeD+oaCDRMbPTYe3kTYlLzpp3yT/LL8V5vDN3cXKBVsLBjf4rGlpVCikF84stV2a9021DbutoHt5turtn8sYhddLTYprih+X8IqufqN6TeV33zaEb9joNSydP9OzE7ezuFdDrsOl0mX5ZaN7/bb3VFOLy8qf7UnZs+VimUVdXsJe4V7Ryt9K7uqNKp2Vr2vTqy+XeNc01arWLu9dn4fe9/Qfsf9rXVKdcV17w5wD9yp96jvaNBqqDiIOZh58EljWGPft4xvm5sUmoqbPhziHRo9HHS4t9mqufmI4pHSFrhF2DJ9NProje9cv+tqNWytb6O1FR8Dx4THnn4f+/3wcZ/jPScYJ1p/0Pyhtp3SXtQBdeR0zHYmdo52RXYNnvQ+2dNt293+o9GPh06pnqo5LXu69AzhTMGZT2dzz86dSz83cz7h/HhPTM/9CxEXbvUG9g5c9Ll4+ZL7pQt9Tn1nL9tdPnXF5srJq4yrndcsr3X0W/S3/2TxU/uA5UDHdavrXTesb3QPLh88M+QwdP6m681Lt7xuXbu94vbgcOjwnZHokdE77DtTd1PuvriXeW/h/sYH6AdFD6UeVjxSfNTws+7PbaOWo6fHXMf6Hwc/vj/OGn/2S8Yv7ycKnpCfVEyqTDZPmU2dmnafvvF05dOJZ+nPFmYKf5X+tfa5zvMffnP8rX82YnbiBf/Fp99LXsq/PPRq2aueuYC5R69TXy/MF72Rf3P4LeNt37vwd5MLWe+x7ys/6H7o/ujz8cGn1E+f/gUDmPP8usTo0wAAAAlwSFlzAAAOxAAADsQBlSsOGwAAASBJREFUOE+l0q1LBGEQx/FdMMsVg/H+AG1WmxqMZ1WDWC5dUMQiyImIQVARRTGpRVHwpYigd/iCmLQZBINYD8yG576/Y0Y27AOehs/O7PA8s/PwbBJC+JfcYjuStG/Y9WAML9jAE0ZQRGuNNhBDlm+exDvqKmLP4hXeMIifBv515Xp04Rrb2MIdZiyu4NB0xBos4RZzOMYNplHDPhZwj7JvylJBo+tFi78s37X4iSPLa7EGq9D441jDJkattowJy+e9gaLnenwogcb/tvzAYgMXltdjE1Rwjins4ARli+uYhZqUYhN04gFqoi+/ompRt6Kr1XRpbAIZwjMuVYQf4QyP6EX0P3DdGMApFqEj9KOA1prcCbzbX+UW25Fb/L2QNAG8ROHz0OoHewAAAABJRU5ErkJggg==Browser ClientGE.PInheritedfalseAnyAnyfalsefalseNoYesActiveXVirtualDynamicActiveXListfalseNoYesBrowser Plug-in Object (BHO)VirtualDynamicBHOList + A representation of an browser plugin. + falseSE.P.TMCore.PlugInCentered on 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Browser and ActiveX PluginsGE.PInheritedfalseAnyAnyfalsefalseManagedCode TypeVirtualStaticcodeTypeList + A representation of an Web Server Process. + falseSE.P.TMCore.WebServerCentered on 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 ServerGE.PInheritedfalseAnyAnyfalsefalseLocalWebContextVirtualDynamiccontextListfalseNot SelectedYesNoDocuments Library capabilityVirtualDynamicdocumentsLibraryListfalseNot SelectedYesNoEnterprise Authentication capabilityVirtualDynamicenterprizeAuthenticationListfalseNot SelectedYesNoInternet (Client & Server) capabilityVirtualDynamicinternetClientServerListfalseNot SelectedYesNoInternet (Client) capabilityVirtualDynamicinternetClientListfalseNot SelectedYesNoLocation capabilityVirtualDynamiclocationListfalseNot SelectedYesNoMicrophone capabilityVirtualDynamicmicrophoneListfalseNot SelectedYesNoMusic Library capabilityVirtualDynamicmusicLibraryListfalseNot SelectedYesNoPictures Library capabilityVirtualDynamicpictureLibraryListfalseNot SelectedYesNoPrivate Networks (Client & Server) capabilityVirtualDynamicprivateNetworkClientServerListfalseNot SelectedYesNoProximity capabilityVirtualDynamicproximityListfalseNot SelectedYesNoRemovable Storage capabilityVirtualDynamicremovableStorageListfalseNot SelectedYesNoShared User Certificates capabilityVirtualDynamicsharedUserCertificatesListfalseNot SelectedYesNoText Messaging capabilityVirtualDynamicsmsListfalseNot SelectedYesNoVideos Library capabilityVirtualDynamicvideosLibraryListfalseNot SelectedYesNoWebcam capabilityVirtualDynamicwebcamListfalseManagedCode TypeVirtualStaticcodeTypeList + A representation of a Windows Store process. + falseSE.P.TMCore.ModernCentered on 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Windows Store ProcessGE.PInheritedfalseAnyAnyfalsefalseUnmanagedCode TypeVirtualStaticcodeTypeList + A representation of an network process or service. + falseSE.P.TMCore.Win32ServiceCentered on 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 ServiceGE.PInheritedfalseAnyAnyfalsefalseUnmanagedCode TypeVirtualStaticcodeTypeList + Delivers web content to a human user. + falseSE.P.TMCore.WebAppCentered on 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 ApplicationGE.PInheritedfalseAnyAnyfalsefalseUnmanagedCode TypeVirtualStaticcodeTypeList + Exposes a programmatic interface. + falseSE.P.TMCore.WebSvcCentered on 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 ServiceGE.PInheritedfalseAnyAnyfalse + A virtual machine running in a Hyper-V partition. + falseSE.P.TMCore.VMCentered on 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Virtual MachineGE.PInheritedfalseAnyAnyfalse + Microsoft applications running on operating systems from Google or Apple. + falseSE.P.TMCore.NonMSCentered on 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Applications Running on a non Microsoft OSGE.PInheritedfalseAnyAnyfalsefalseCodeTypeVirtualStatictypeList + A representation of an external Web browser. + falseSE.EI.TMCore.BrowserLower right of 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BrowserGE.EIInheritedfalseAnyAnyfalse + A representation of an external authorization provider. + falseSE.EI.TMCore.AuthProviderLower right of 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 ProviderGE.EIInheritedfalseAnyAnyfalsefalseCodeTypeVirtualStatictypeList + A representation of an external Web application (portal, front ed, etc.). + falseSE.EI.TMCore.WebAppLower right of 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 Web ApplicationGE.EIInheritedfalseAnyAnyfalsefalseCodeTypeVirtualStatictypeList + A representation of an external Web service. + falseSE.EI.TMCore.WebSvcLower right of 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 Web ServiceGE.EIInheritedfalseAnyAnyfalsefalseHumanTypeVirtualStatictypeList + A representation of a user. + falseSE.EI.TMCore.UserLower right of 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Human UserGE.EIInheritedfalseAnyAnyfalse + A large service that has only one instance on the Internet, for example, Outlook.com and Xbox Live. + falseSE.EI.TMCore.MegasevriceLower right of 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.EIInheritedfalseAnyAnyfalsefalseNot ApplicableAuthenticates ItselfVirtualStaticauthenticatesItselfListfalseCodeTypeVirtualStatictypeList + Represents the point where an application calls into an unmanaged runtime library such as the CRT. + falseSE.EI.TMCore.CRTLower right of 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Windows RuntimeGE.EIInheritedfalseAnyAnyfalsefalseNot ApplicableAuthenticates ItselfVirtualStaticauthenticatesItselfListfalseCodeTypeVirtualStatictypeList + Represents the point where an application calls into the .NET Framework. + falseSE.EI.TMCore.NFXLower right of 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Windows .NET RuntimeGE.EIInheritedfalseAnyAnyfalsefalseNot ApplicableAuthenticates ItselfVirtualStaticauthenticatesItselfListfalseCodeTypeVirtualStatictypeList + Represents the point where an application calls into WinRT. + falseSE.EI.TMCore.WinRTLower right of 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Windows RT RuntimeGE.EIInheritedfalseAnyAnyfalse + A representation of a Cloud Storage. + falseSE.DS.TMCore.CloudStorageLower right of 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Cloud StorageGE.DSInheritedfalseAnyAnyfalsefalseSQL Relational DatabaseStore TypeVirtualStaticstoreTypeList + A representation of a SQL Database. + falseSE.DS.TMCore.SQLLower right of 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 DatabaseGE.DSInheritedfalseAnyAnyfalsefalseNon Relational DatabaseStore TypeVirtualStaticstoreTypeList + A representation of a non-relational database. + falseSE.DS.TMCore.NoSQLLower right of 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Non Relational DatabaseGE.DSInheritedfalseAnyAnyfalsefalseNTFSExFATFATReFSIFSUDFOtherFile System TypeVirtualDynamicfsTypeListfalseFile SystemStore TypeVirtualStaticstoreTypeList + A representation of a file system. + falseSE.DS.TMCore.FSLower right of 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File SystemGE.DSInheritedfalseAnyAnyfalsefalseRegistryStore TypeVirtualStaticstoreTypeList + A representation of a Registry. + falseSE.DS.TMCore.RegistryLower right of stenciliVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGOfPtRkwAAACBjSFJNAACHDwAAjA8AAP1SAACBQAAAfXkAAOmLAAA85QAAGcxzPIV3AAAKOWlDQ1BQaG90b3Nob3AgSUNDIHByb2ZpbGUAAEjHnZZ3VFTXFofPvXd6oc0wAlKG3rvAANJ7k15FYZgZYCgDDjM0sSGiAhFFRJoiSFDEgNFQJFZEsRAUVLAHJAgoMRhFVCxvRtaLrqy89/Ly++Osb+2z97n77L3PWhcAkqcvl5cGSwGQyhPwgzyc6RGRUXTsAIABHmCAKQBMVka6X7B7CBDJy82FniFyAl8EAfB6WLwCcNPQM4BOB/+fpFnpfIHomAARm7M5GSwRF4g4JUuQLrbPipgalyxmGCVmvihBEcuJOWGRDT77LLKjmNmpPLaIxTmns1PZYu4V8bZMIUfEiK+ICzO5nCwR3xKxRoowlSviN+LYVA4zAwAUSWwXcFiJIjYRMYkfEuQi4uUA4EgJX3HcVyzgZAvEl3JJS8/hcxMSBXQdli7d1NqaQffkZKVwBALDACYrmcln013SUtOZvBwAFu/8WTLi2tJFRbY0tba0NDQzMv2qUP91829K3NtFehn4uWcQrf+L7a/80hoAYMyJarPziy2uCoDOLQDI3fti0zgAgKSobx3Xv7oPTTwviQJBuo2xcVZWlhGXwzISF/QP/U+Hv6GvvmckPu6P8tBdOfFMYYqALq4bKy0lTcinZ6QzWRy64Z+H+B8H/nUeBkGceA6fwxNFhImmjMtLELWbx+YKuGk8Opf3n5r4D8P+pMW5FonS+BFQY4yA1HUqQH7tBygKESDR+8Vd/6NvvvgwIH554SqTi3P/7zf9Z8Gl4iWDm/A5ziUohM4S8jMX98TPEqABAUgCKpAHykAd6ABDYAasgC1wBG7AG/iDEBAJVgMWSASpgA+yQB7YBApBMdgJ9oBqUAcaQTNoBcdBJzgFzoNL4Bq4AW6D+2AUTIBnYBa8BgsQBGEhMkSB5CEVSBPSh8wgBmQPuUG+UBAUCcVCCRAPEkJ50GaoGCqDqqF6qBn6HjoJnYeuQIPQXWgMmoZ+h97BCEyCqbASrAUbwwzYCfaBQ+BVcAK8Bs6FC+AdcCXcAB+FO+Dz8DX4NjwKP4PnEIAQERqiihgiDMQF8UeikHiEj6xHipAKpAFpRbqRPuQmMorMIG9RGBQFRUcZomxRnqhQFAu1BrUeVYKqRh1GdaB6UTdRY6hZ1Ec0Ga2I1kfboL3QEegEdBa6EF2BbkK3oy+ib6Mn0K8xGAwNo42xwnhiIjFJmLWYEsw+TBvmHGYQM46Zw2Kx8lh9rB3WH8vECrCF2CrsUexZ7BB2AvsGR8Sp4Mxw7rgoHA+Xj6vAHcGdwQ3hJnELeCm8Jt4G749n43PwpfhGfDf+On4Cv0CQJmgT7AghhCTCJkIloZVwkfCA8JJIJKoRrYmBRC5xI7GSeIx4mThGfEuSIemRXEjRJCFpB+kQ6RzpLuklmUzWIjuSo8gC8g5yM/kC+RH5jQRFwkjCS4ItsUGiRqJDYkjiuSReUlPSSXK1ZK5kheQJyeuSM1J4KS0pFymm1HqpGqmTUiNSc9IUaVNpf+lU6RLpI9JXpKdksDJaMm4ybJkCmYMyF2TGKQhFneJCYVE2UxopFykTVAxVm+pFTaIWU7+jDlBnZWVkl8mGyWbL1sielh2lITQtmhcthVZKO04bpr1borTEaQlnyfYlrUuGlszLLZVzlOPIFcm1yd2WeydPl3eTT5bfJd8p/1ABpaCnEKiQpbBf4aLCzFLqUtulrKVFS48vvacIK+opBimuVTyo2K84p6Ss5KGUrlSldEFpRpmm7KicpFyufEZ5WoWiYq/CVSlXOavylC5Ld6Kn0CvpvfRZVUVVT1Whar3qgOqCmrZaqFq+WpvaQ3WCOkM9Xr1cvUd9VkNFw08jT6NF454mXpOhmai5V7NPc15LWytca6tWp9aUtpy2l3audov2Ax2yjoPOGp0GnVu6GF2GbrLuPt0berCehV6iXo3edX1Y31Kfq79Pf9AAbWBtwDNoMBgxJBk6GWYathiOGdGMfI3yjTqNnhtrGEcZ7zLuM/5oYmGSYtJoct9UxtTbNN+02/R3Mz0zllmN2S1zsrm7+QbzLvMXy/SXcZbtX3bHgmLhZ7HVosfig6WVJd+y1XLaSsMq1qrWaoRBZQQwShiXrdHWztYbrE9Zv7WxtBHYHLf5zdbQNtn2iO3Ucu3lnOWNy8ft1OyYdvV2o/Z0+1j7A/ajDqoOTIcGh8eO6o5sxybHSSddpySno07PnU2c+c7tzvMuNi7rXM65Iq4erkWuA24ybqFu1W6P3NXcE9xb3Gc9LDzWepzzRHv6eO7yHPFS8mJ5NXvNelt5r/Pu9SH5BPtU+zz21fPl+3b7wX7efrv9HqzQXMFb0ekP/L38d/s/DNAOWBPwYyAmMCCwJvBJkGlQXlBfMCU4JvhI8OsQ55DSkPuhOqHC0J4wybDosOaw+XDX8LLw0QjjiHUR1yIVIrmRXVHYqLCopqi5lW4r96yciLaILoweXqW9KnvVldUKq1NWn46RjGHGnIhFx4bHHol9z/RnNjDn4rziauNmWS6svaxnbEd2OXuaY8cp40zG28WXxU8l2CXsTphOdEisSJzhunCruS+SPJPqkuaT/ZMPJX9KCU9pS8Wlxqae5Mnwknm9acpp2WmD6frphemja2zW7Fkzy/fhN2VAGasyugRU0c9Uv1BHuEU4lmmfWZP5Jiss60S2dDYvuz9HL2d7zmSue+63a1FrWWt78lTzNuWNrXNaV78eWh+3vmeD+oaCDRMbPTYe3kTYlLzpp3yT/LL8V5vDN3cXKBVsLBjf4rGlpVCikF84stV2a9021DbutoHt5turtn8sYhddLTYprih+X8IqufqN6TeV33zaEb9joNSydP9OzE7ezuFdDrsOl0mX5ZaN7/bb3VFOLy8qf7UnZs+VimUVdXsJe4V7Ryt9K7uqNKp2Vr2vTqy+XeNc01arWLu9dn4fe9/Qfsf9rXVKdcV17w5wD9yp96jvaNBqqDiIOZh58EljWGPft4xvm5sUmoqbPhziHRo9HHS4t9mqufmI4pHSFrhF2DJ9NProje9cv+tqNWytb6O1FR8Dx4THnn4f+/3wcZ/jPScYJ1p/0Pyhtp3SXtQBdeR0zHYmdo52RXYNnvQ+2dNt293+o9GPh06pnqo5LXu69AzhTMGZT2dzz86dSz83cz7h/HhPTM/9CxEXbvUG9g5c9Ll4+ZL7pQt9Tn1nL9tdPnXF5srJq4yrndcsr3X0W/S3/2TxU/uA5UDHdavrXTesb3QPLh88M+QwdP6m681Lt7xuXbu94vbgcOjwnZHokdE77DtTd1PuvriXeW/h/sYH6AdFD6UeVjxSfNTws+7PbaOWo6fHXMf6Hwc/vj/OGn/2S8Yv7ycKnpCfVEyqTDZPmU2dmnafvvF05dOJZ+nPFmYKf5X+tfa5zvMffnP8rX82YnbiBf/Fp99LXsq/PPRq2aueuYC5R69TXy/MF72Rf3P4LeNt37vwd5MLWe+x7ys/6H7o/ujz8cGn1E+f/gUDmPP8usTo0wAAAAlwSFlzAAAOxAAADsQBlSsOGwAAAZxJREFUOE+Vkr1LQlEYxm9lSyFlUEuEEEFDxJ3KOxSSUEFqYoVJECoEQYt97eocqHO0VNgm0hC4hBQ0BEUNLUFQTbVV9Afcnudwj5x7uUENv3vPed6Pc877vpppmoKWsbAOaiAotb8gPgjKAbN/bvW0dTzyiXUJdDmd3RDBbYHI1275YAfCSKXeSHLfbswXnM5uaP5ouszTEfSKf8wTiF5wT90twEkzgRNnAmgpEFM1oqXzxXD3VOJJDe6cXHinbgX6QUOxs9DN+vDjBYaR2T6iw2hyo3r98DhLHfusVVShD4RTV1yDDyBuo15nEEyDYeCBgzi1YyL+ZhWYup4plHIo8LeVqKYmsEEHPuXw7HwJe59i62WnrAT2IBXpgCe84N8cLqxj8llEikGQlU6WJhwUOFwsoE2nY4kZvcHFOtZ3QP8lgSvCcau4v4kgvSe0fIsCXf47gcUz/75Q4oYJWHkWUbHb4OzsHVfXNaUlgqH42gkTAB/ngf1X7YQzA7sBvFoFLembWblnIvYYIvsti+nhXt5GngqNMwO7qf0AFBEVY8ZCOLAAAAAASUVORK5CYII=Registry HiveGE.DSInheritedfalseAnyAnyfalsefalseConfigurationStore TypeVirtualStaticstoreTypeList + A configuration file, this includes XML, INI, and INF files. + falseSE.DS.TMCore.ConfigFileLower right of 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Configuration FileGE.DSInheritedfalseAnyAnyfalsefalseCacheStore TypeVirtualStaticstoreTypeList + A representation of a local data cache. + falseSE.DS.TMCore.CacheLower right of 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CacheGE.DSInheritedfalseAnyAnyfalsefalseHTML5 StorageStore TypeVirtualStaticstoreTypeList + A representation of HTML5 local storage. + falseSE.DS.TMCore.HTML5LSLower right of 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HTML5 Local StorageGE.DSInheritedfalseAnyAnyfalsefalseNoYesHTTPOnlyVirtualDynamicHTTPOnlyListfalseCookieStore TypeVirtualStaticstoreTypeList + A representation of cookie storage. + falseSE.DS.TMCore.CookieLower right of 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CookiesGE.DSInheritedfalseAnyAnyfalsefalseNoYesGPSVirtualDynamicGPSListfalseNoYesContactsVirtualDynamicContactsListfalseNoYesCalendar EventsVirtualDynamicCalendarListfalseNoYesSMS messagesVirtualDynamicSMSmessagesListfalseNoYesCached CredentialsVirtualDynamicCredsListfalseNoYesEnterprise DataVirtualDynamicEnterpriseListfalseNoYesMessaging Data (Mail, IM, SMS)VirtualDynamice-mailListfalseNoYesSIM StorageVirtualDynamicSIMListfalseNoYesOther DataVirtualDynamicmiscListfalseDeviceStore TypeVirtualStaticstoreTypeList + A representation of device local storage. + falseSE.DS.TMCore.DeviceLower right of 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.DSInheritedfalseAnyAnyfalsefalseNoSource AuthenticatedVirtualStaticauthenticatesSourceListfalseNoDestination AuthenticatedVirtualStaticauthenticatesDestinationListfalseNoProvides ConfidentialityVirtualStaticprovidesConfidentialityListfalseNoProvides IntegrityVirtualStaticprovidesIntegrityList + A representation of an HTTP data flow. + falseSE.DF.TMCore.HTTPBefore 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.DFInheritedfalseAnyAnyfalsefalseYesDestination AuthenticatedVirtualStaticauthenticatesDestinationListfalseYesProvides ConfidentialityVirtualStaticprovidesConfidentialityListfalseYesProvides IntegrityVirtualStaticprovidesIntegrityList + A representation of an HTTPS data flow. + falseSE.DF.TMCore.HTTPSBefore labeliVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGOfPtRkwAAACBjSFJNAACHDwAAjA8AAP1SAACBQAAAfXkAAOmLAAA85QAAGcxzPIV3AAAKOWlDQ1BQaG90b3Nob3AgSUNDIHByb2ZpbGUAAEjHnZZ3VFTXFofPvXd6oc0wAlKG3rvAANJ7k15FYZgZYCgDDjM0sSGiAhFFRJoiSFDEgNFQJFZEsRAUVLAHJAgoMRhFVCxvRtaLrqy89/Ly++Osb+2z97n77L3PWhcAkqcvl5cGSwGQyhPwgzyc6RGRUXTsAIABHmCAKQBMVka6X7B7CBDJy82FniFyAl8EAfB6WLwCcNPQM4BOB/+fpFnpfIHomAARm7M5GSwRF4g4JUuQLrbPipgalyxmGCVmvihBEcuJOWGRDT77LLKjmNmpPLaIxTmns1PZYu4V8bZMIUfEiK+ICzO5nCwR3xKxRoowlSviN+LYVA4zAwAUSWwXcFiJIjYRMYkfEuQi4uUA4EgJX3HcVyzgZAvEl3JJS8/hcxMSBXQdli7d1NqaQffkZKVwBALDACYrmcln013SUtOZvBwAFu/8WTLi2tJFRbY0tba0NDQzMv2qUP91829K3NtFehn4uWcQrf+L7a/80hoAYMyJarPziy2uCoDOLQDI3fti0zgAgKSobx3Xv7oPTTwviQJBuo2xcVZWlhGXwzISF/QP/U+Hv6GvvmckPu6P8tBdOfFMYYqALq4bKy0lTcinZ6QzWRy64Z+H+B8H/nUeBkGceA6fwxNFhImmjMtLELWbx+YKuGk8Opf3n5r4D8P+pMW5FonS+BFQY4yA1HUqQH7tBygKESDR+8Vd/6NvvvgwIH554SqTi3P/7zf9Z8Gl4iWDm/A5ziUohM4S8jMX98TPEqABAUgCKpAHykAd6ABDYAasgC1wBG7AG/iDEBAJVgMWSASpgA+yQB7YBApBMdgJ9oBqUAcaQTNoBcdBJzgFzoNL4Bq4AW6D+2AUTIBnYBa8BgsQBGEhMkSB5CEVSBPSh8wgBmQPuUG+UBAUCcVCCRAPEkJ50GaoGCqDqqF6qBn6HjoJnYeuQIPQXWgMmoZ+h97BCEyCqbASrAUbwwzYCfaBQ+BVcAK8Bs6FC+AdcCXcAB+FO+Dz8DX4NjwKP4PnEIAQERqiihgiDMQF8UeikHiEj6xHipAKpAFpRbqRPuQmMorMIG9RGBQFRUcZomxRnqhQFAu1BrUeVYKqRh1GdaB6UTdRY6hZ1Ec0Ga2I1kfboL3QEegEdBa6EF2BbkK3oy+ib6Mn0K8xGAwNo42xwnhiIjFJmLWYEsw+TBvmHGYQM46Zw2Kx8lh9rB3WH8vECrCF2CrsUexZ7BB2AvsGR8Sp4Mxw7rgoHA+Xj6vAHcGdwQ3hJnELeCm8Jt4G749n43PwpfhGfDf+On4Cv0CQJmgT7AghhCTCJkIloZVwkfCA8JJIJKoRrYmBRC5xI7GSeIx4mThGfEuSIemRXEjRJCFpB+kQ6RzpLuklmUzWIjuSo8gC8g5yM/kC+RH5jQRFwkjCS4ItsUGiRqJDYkjiuSReUlPSSXK1ZK5kheQJyeuSM1J4KS0pFymm1HqpGqmTUiNSc9IUaVNpf+lU6RLpI9JXpKdksDJaMm4ybJkCmYMyF2TGKQhFneJCYVE2UxopFykTVAxVm+pFTaIWU7+jDlBnZWVkl8mGyWbL1sielh2lITQtmhcthVZKO04bpr1borTEaQlnyfYlrUuGlszLLZVzlOPIFcm1yd2WeydPl3eTT5bfJd8p/1ABpaCnEKiQpbBf4aLCzFLqUtulrKVFS48vvacIK+opBimuVTyo2K84p6Ss5KGUrlSldEFpRpmm7KicpFyufEZ5WoWiYq/CVSlXOavylC5Ld6Kn0CvpvfRZVUVVT1Whar3qgOqCmrZaqFq+WpvaQ3WCOkM9Xr1cvUd9VkNFw08jT6NF454mXpOhmai5V7NPc15LWytca6tWp9aUtpy2l3audov2Ax2yjoPOGp0GnVu6GF2GbrLuPt0berCehV6iXo3edX1Y31Kfq79Pf9AAbWBtwDNoMBgxJBk6GWYathiOGdGMfI3yjTqNnhtrGEcZ7zLuM/5oYmGSYtJoct9UxtTbNN+02/R3Mz0zllmN2S1zsrm7+QbzLvMXy/SXcZbtX3bHgmLhZ7HVosfig6WVJd+y1XLaSsMq1qrWaoRBZQQwShiXrdHWztYbrE9Zv7WxtBHYHLf5zdbQNtn2iO3Ucu3lnOWNy8ft1OyYdvV2o/Z0+1j7A/ajDqoOTIcGh8eO6o5sxybHSSddpySno07PnU2c+c7tzvMuNi7rXM65Iq4erkWuA24ybqFu1W6P3NXcE9xb3Gc9LDzWepzzRHv6eO7yHPFS8mJ5NXvNelt5r/Pu9SH5BPtU+zz21fPl+3b7wX7efrv9HqzQXMFb0ekP/L38d/s/DNAOWBPwYyAmMCCwJvBJkGlQXlBfMCU4JvhI8OsQ55DSkPuhOqHC0J4wybDosOaw+XDX8LLw0QjjiHUR1yIVIrmRXVHYqLCopqi5lW4r96yciLaILoweXqW9KnvVldUKq1NWn46RjGHGnIhFx4bHHol9z/RnNjDn4rziauNmWS6svaxnbEd2OXuaY8cp40zG28WXxU8l2CXsTphOdEisSJzhunCruS+SPJPqkuaT/ZMPJX9KCU9pS8Wlxqae5Mnwknm9acpp2WmD6frphemja2zW7Fkzy/fhN2VAGasyugRU0c9Uv1BHuEU4lmmfWZP5Jiss60S2dDYvuz9HL2d7zmSue+63a1FrWWt78lTzNuWNrXNaV78eWh+3vmeD+oaCDRMbPTYe3kTYlLzpp3yT/LL8V5vDN3cXKBVsLBjf4rGlpVCikF84stV2a9021DbutoHt5turtn8sYhddLTYprih+X8IqufqN6TeV33zaEb9joNSydP9OzE7ezuFdDrsOl0mX5ZaN7/bb3VFOLy8qf7UnZs+VimUVdXsJe4V7Ryt9K7uqNKp2Vr2vTqy+XeNc01arWLu9dn4fe9/Qfsf9rXVKdcV17w5wD9yp96jvaNBqqDiIOZh58EljWGPft4xvm5sUmoqbPhziHRo9HHS4t9mqufmI4pHSFrhF2DJ9NProje9cv+tqNWytb6O1FR8Dx4THnn4f+/3wcZ/jPScYJ1p/0Pyhtp3SXtQBdeR0zHYmdo52RXYNnvQ+2dNt293+o9GPh06pnqo5LXu69AzhTMGZT2dzz86dSz83cz7h/HhPTM/9CxEXbvUG9g5c9Ll4+ZL7pQt9Tn1nL9tdPnXF5srJq4yrndcsr3X0W/S3/2TxU/uA5UDHdavrXTesb3QPLh88M+QwdP6m681Lt7xuXbu94vbgcOjwnZHokdE77DtTd1PuvriXeW/h/sYH6AdFD6UeVjxSfNTws+7PbaOWo6fHXMf6Hwc/vj/OGn/2S8Yv7ycKnpCfVEyqTDZPmU2dmnafvvF05dOJZ+nPFmYKf5X+tfa5zvMffnP8rX82YnbiBf/Fp99LXsq/PPRq2aueuYC5R69TXy/MF72Rf3P4LeNt37vwd5MLWe+x7ys/6H7o/ujz8cGn1E+f/gUDmPP8usTo0wAAAAlwSFlzAAAOxAAADsQBlSsOGwAAAP9JREFUOE+10s1mQ0EYxvFECCGr3EcI0dBVKeFw6B1kFULpKqvSVSkl5A5yE9lmFbINJWSVVbZZhRBKmf6f8U5NT9pptbL4OWfmvO8zH06pfJG7/zh7wAzX6GCIFT7VpALWqDrnSoHGeLbvXirgMWp8wAKZjSfwdamApyhgbnNvuEQdW82lApZRwBVebX5kc/4oqQDxW7aGNkZo2riPkwDd8tTete1aCCji21h1xYAXNHAP38yzC61WiZqbOOAjYIM9dK67qDDDEarZQf/FErpMv2gI0HZaGBSaw8V9KwRIL2rO8WOzhAAV1635xsYnxV+Jd6CLusWvmyUO+IPcvQN8C4wQAsHzwgAAAABJRU5ErkJggg==HTTPSGE.DFInheritedfalseAnyAnyfalse + A representation of an Binary data flow. + falseSE.DF.TMCore.BinaryBefore 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BinaryGE.DFInheritedfalseAnyAnyfalsefalseYesSource AuthenticatedVirtualStaticauthenticatesSourceListfalseYesDestination AuthenticatedVirtualStaticauthenticatesDestinationListfalseYesProvides ConfidentialityVirtualStaticprovidesConfidentialityListfalseYesProvides IntegrityVirtualStaticprovidesIntegrityList + A representation of an IPsec data flow. + falseSE.DF.TMCore.IPsecBefore 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.DFInheritedfalseAnyAnyfalse + A representation of a named pipe data flow. + falseSE.DF.TMCore.NamedPipeBefore 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Named PipeGE.DFInheritedfalseAnyAnyfalse + A representation of a SMBv1 or SMBv2 data flow. + falseSE.DF.TMCore.SMBBefore labeliVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGOfPtRkwAAACBjSFJNAACHDwAAjA8AAP1SAACBQAAAfXkAAOmLAAA85QAAGcxzPIV3AAAKOWlDQ1BQaG90b3Nob3AgSUNDIHByb2ZpbGUAAEjHnZZ3VFTXFofPvXd6oc0wAlKG3rvAANJ7k15FYZgZYCgDDjM0sSGiAhFFRJoiSFDEgNFQJFZEsRAUVLAHJAgoMRhFVCxvRtaLrqy89/Ly++Osb+2z97n77L3PWhcAkqcvl5cGSwGQyhPwgzyc6RGRUXTsAIABHmCAKQBMVka6X7B7CBDJy82FniFyAl8EAfB6WLwCcNPQM4BOB/+fpFnpfIHomAARm7M5GSwRF4g4JUuQLrbPipgalyxmGCVmvihBEcuJOWGRDT77LLKjmNmpPLaIxTmns1PZYu4V8bZMIUfEiK+ICzO5nCwR3xKxRoowlSviN+LYVA4zAwAUSWwXcFiJIjYRMYkfEuQi4uUA4EgJX3HcVyzgZAvEl3JJS8/hcxMSBXQdli7d1NqaQffkZKVwBALDACYrmcln013SUtOZvBwAFu/8WTLi2tJFRbY0tba0NDQzMv2qUP91829K3NtFehn4uWcQrf+L7a/80hoAYMyJarPziy2uCoDOLQDI3fti0zgAgKSobx3Xv7oPTTwviQJBuo2xcVZWlhGXwzISF/QP/U+Hv6GvvmckPu6P8tBdOfFMYYqALq4bKy0lTcinZ6QzWRy64Z+H+B8H/nUeBkGceA6fwxNFhImmjMtLELWbx+YKuGk8Opf3n5r4D8P+pMW5FonS+BFQY4yA1HUqQH7tBygKESDR+8Vd/6NvvvgwIH554SqTi3P/7zf9Z8Gl4iWDm/A5ziUohM4S8jMX98TPEqABAUgCKpAHykAd6ABDYAasgC1wBG7AG/iDEBAJVgMWSASpgA+yQB7YBApBMdgJ9oBqUAcaQTNoBcdBJzgFzoNL4Bq4AW6D+2AUTIBnYBa8BgsQBGEhMkSB5CEVSBPSh8wgBmQPuUG+UBAUCcVCCRAPEkJ50GaoGCqDqqF6qBn6HjoJnYeuQIPQXWgMmoZ+h97BCEyCqbASrAUbwwzYCfaBQ+BVcAK8Bs6FC+AdcCXcAB+FO+Dz8DX4NjwKP4PnEIAQERqiihgiDMQF8UeikHiEj6xHipAKpAFpRbqRPuQmMorMIG9RGBQFRUcZomxRnqhQFAu1BrUeVYKqRh1GdaB6UTdRY6hZ1Ec0Ga2I1kfboL3QEegEdBa6EF2BbkK3oy+ib6Mn0K8xGAwNo42xwnhiIjFJmLWYEsw+TBvmHGYQM46Zw2Kx8lh9rB3WH8vECrCF2CrsUexZ7BB2AvsGR8Sp4Mxw7rgoHA+Xj6vAHcGdwQ3hJnELeCm8Jt4G749n43PwpfhGfDf+On4Cv0CQJmgT7AghhCTCJkIloZVwkfCA8JJIJKoRrYmBRC5xI7GSeIx4mThGfEuSIemRXEjRJCFpB+kQ6RzpLuklmUzWIjuSo8gC8g5yM/kC+RH5jQRFwkjCS4ItsUGiRqJDYkjiuSReUlPSSXK1ZK5kheQJyeuSM1J4KS0pFymm1HqpGqmTUiNSc9IUaVNpf+lU6RLpI9JXpKdksDJaMm4ybJkCmYMyF2TGKQhFneJCYVE2UxopFykTVAxVm+pFTaIWU7+jDlBnZWVkl8mGyWbL1sielh2lITQtmhcthVZKO04bpr1borTEaQlnyfYlrUuGlszLLZVzlOPIFcm1yd2WeydPl3eTT5bfJd8p/1ABpaCnEKiQpbBf4aLCzFLqUtulrKVFS48vvacIK+opBimuVTyo2K84p6Ss5KGUrlSldEFpRpmm7KicpFyufEZ5WoWiYq/CVSlXOavylC5Ld6Kn0CvpvfRZVUVVT1Whar3qgOqCmrZaqFq+WpvaQ3WCOkM9Xr1cvUd9VkNFw08jT6NF454mXpOhmai5V7NPc15LWytca6tWp9aUtpy2l3audov2Ax2yjoPOGp0GnVu6GF2GbrLuPt0berCehV6iXo3edX1Y31Kfq79Pf9AAbWBtwDNoMBgxJBk6GWYathiOGdGMfI3yjTqNnhtrGEcZ7zLuM/5oYmGSYtJoct9UxtTbNN+02/R3Mz0zllmN2S1zsrm7+QbzLvMXy/SXcZbtX3bHgmLhZ7HVosfig6WVJd+y1XLaSsMq1qrWaoRBZQQwShiXrdHWztYbrE9Zv7WxtBHYHLf5zdbQNtn2iO3Ucu3lnOWNy8ft1OyYdvV2o/Z0+1j7A/ajDqoOTIcGh8eO6o5sxybHSSddpySno07PnU2c+c7tzvMuNi7rXM65Iq4erkWuA24ybqFu1W6P3NXcE9xb3Gc9LDzWepzzRHv6eO7yHPFS8mJ5NXvNelt5r/Pu9SH5BPtU+zz21fPl+3b7wX7efrv9HqzQXMFb0ekP/L38d/s/DNAOWBPwYyAmMCCwJvBJkGlQXlBfMCU4JvhI8OsQ55DSkPuhOqHC0J4wybDosOaw+XDX8LLw0QjjiHUR1yIVIrmRXVHYqLCopqi5lW4r96yciLaILoweXqW9KnvVldUKq1NWn46RjGHGnIhFx4bHHol9z/RnNjDn4rziauNmWS6svaxnbEd2OXuaY8cp40zG28WXxU8l2CXsTphOdEisSJzhunCruS+SPJPqkuaT/ZMPJX9KCU9pS8Wlxqae5Mnwknm9acpp2WmD6frphemja2zW7Fkzy/fhN2VAGasyugRU0c9Uv1BHuEU4lmmfWZP5Jiss60S2dDYvuz9HL2d7zmSue+63a1FrWWt78lTzNuWNrXNaV78eWh+3vmeD+oaCDRMbPTYe3kTYlLzpp3yT/LL8V5vDN3cXKBVsLBjf4rGlpVCikF84stV2a9021DbutoHt5turtn8sYhddLTYprih+X8IqufqN6TeV33zaEb9joNSydP9OzE7ezuFdDrsOl0mX5ZaN7/bb3VFOLy8qf7UnZs+VimUVdXsJe4V7Ryt9K7uqNKp2Vr2vTqy+XeNc01arWLu9dn4fe9/Qfsf9rXVKdcV17w5wD9yp96jvaNBqqDiIOZh58EljWGPft4xvm5sUmoqbPhziHRo9HHS4t9mqufmI4pHSFrhF2DJ9NProje9cv+tqNWytb6O1FR8Dx4THnn4f+/3wcZ/jPScYJ1p/0Pyhtp3SXtQBdeR0zHYmdo52RXYNnvQ+2dNt293+o9GPh06pnqo5LXu69AzhTMGZT2dzz86dSz83cz7h/HhPTM/9CxEXbvUG9g5c9Ll4+ZL7pQt9Tn1nL9tdPnXF5srJq4yrndcsr3X0W/S3/2TxU/uA5UDHdavrXTesb3QPLh88M+QwdP6m681Lt7xuXbu94vbgcOjwnZHokdE77DtTd1PuvriXeW/h/sYH6AdFD6UeVjxSfNTws+7PbaOWo6fHXMf6Hwc/vj/OGn/2S8Yv7ycKnpCfVEyqTDZPmU2dmnafvvF05dOJZ+nPFmYKf5X+tfa5zvMffnP8rX82YnbiBf/Fp99LXsq/PPRq2aueuYC5R69TXy/MF72Rf3P4LeNt37vwd5MLWe+x7ys/6H7o/ujz8cGn1E+f/gUDmPP8usTo0wAAAAlwSFlzAAAOxAAADsQBlSsOGwAAAEhJREFUOE/NzLENACAMA8EwFFNk/3kCpotc2VBg6eTuY8ysGyewF463AbyCAo4WwCso4GgBvIICjhbAKyjgaAG8ggKOjwK+rAUpwkqHruWEswAAAABJRU5ErkJggg==SMBGE.DFInheritedfalseAnyAnyfalse + A representation of an RPC or Distributed COM (DCOM) data flow. + falseSE.DF.TMCore.RPCBefore labeliVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGOfPtRkwAAACBjSFJNAACHDwAAjA8AAP1SAACBQAAAfXkAAOmLAAA85QAAGcxzPIV3AAAKOWlDQ1BQaG90b3Nob3AgSUNDIHByb2ZpbGUAAEjHnZZ3VFTXFofPvXd6oc0wAlKG3rvAANJ7k15FYZgZYCgDDjM0sSGiAhFFRJoiSFDEgNFQJFZEsRAUVLAHJAgoMRhFVCxvRtaLrqy89/Ly++Osb+2z97n77L3PWhcAkqcvl5cGSwGQyhPwgzyc6RGRUXTsAIABHmCAKQBMVka6X7B7CBDJy82FniFyAl8EAfB6WLwCcNPQM4BOB/+fpFnpfIHomAARm7M5GSwRF4g4JUuQLrbPipgalyxmGCVmvihBEcuJOWGRDT77LLKjmNmpPLaIxTmns1PZYu4V8bZMIUfEiK+ICzO5nCwR3xKxRoowlSviN+LYVA4zAwAUSWwXcFiJIjYRMYkfEuQi4uUA4EgJX3HcVyzgZAvEl3JJS8/hcxMSBXQdli7d1NqaQffkZKVwBALDACYrmcln013SUtOZvBwAFu/8WTLi2tJFRbY0tba0NDQzMv2qUP91829K3NtFehn4uWcQrf+L7a/80hoAYMyJarPziy2uCoDOLQDI3fti0zgAgKSobx3Xv7oPTTwviQJBuo2xcVZWlhGXwzISF/QP/U+Hv6GvvmckPu6P8tBdOfFMYYqALq4bKy0lTcinZ6QzWRy64Z+H+B8H/nUeBkGceA6fwxNFhImmjMtLELWbx+YKuGk8Opf3n5r4D8P+pMW5FonS+BFQY4yA1HUqQH7tBygKESDR+8Vd/6NvvvgwIH554SqTi3P/7zf9Z8Gl4iWDm/A5ziUohM4S8jMX98TPEqABAUgCKpAHykAd6ABDYAasgC1wBG7AG/iDEBAJVgMWSASpgA+yQB7YBApBMdgJ9oBqUAcaQTNoBcdBJzgFzoNL4Bq4AW6D+2AUTIBnYBa8BgsQBGEhMkSB5CEVSBPSh8wgBmQPuUG+UBAUCcVCCRAPEkJ50GaoGCqDqqF6qBn6HjoJnYeuQIPQXWgMmoZ+h97BCEyCqbASrAUbwwzYCfaBQ+BVcAK8Bs6FC+AdcCXcAB+FO+Dz8DX4NjwKP4PnEIAQERqiihgiDMQF8UeikHiEj6xHipAKpAFpRbqRPuQmMorMIG9RGBQFRUcZomxRnqhQFAu1BrUeVYKqRh1GdaB6UTdRY6hZ1Ec0Ga2I1kfboL3QEegEdBa6EF2BbkK3oy+ib6Mn0K8xGAwNo42xwnhiIjFJmLWYEsw+TBvmHGYQM46Zw2Kx8lh9rB3WH8vECrCF2CrsUexZ7BB2AvsGR8Sp4Mxw7rgoHA+Xj6vAHcGdwQ3hJnELeCm8Jt4G749n43PwpfhGfDf+On4Cv0CQJmgT7AghhCTCJkIloZVwkfCA8JJIJKoRrYmBRC5xI7GSeIx4mThGfEuSIemRXEjRJCFpB+kQ6RzpLuklmUzWIjuSo8gC8g5yM/kC+RH5jQRFwkjCS4ItsUGiRqJDYkjiuSReUlPSSXK1ZK5kheQJyeuSM1J4KS0pFymm1HqpGqmTUiNSc9IUaVNpf+lU6RLpI9JXpKdksDJaMm4ybJkCmYMyF2TGKQhFneJCYVE2UxopFykTVAxVm+pFTaIWU7+jDlBnZWVkl8mGyWbL1sielh2lITQtmhcthVZKO04bpr1borTEaQlnyfYlrUuGlszLLZVzlOPIFcm1yd2WeydPl3eTT5bfJd8p/1ABpaCnEKiQpbBf4aLCzFLqUtulrKVFS48vvacIK+opBimuVTyo2K84p6Ss5KGUrlSldEFpRpmm7KicpFyufEZ5WoWiYq/CVSlXOavylC5Ld6Kn0CvpvfRZVUVVT1Whar3qgOqCmrZaqFq+WpvaQ3WCOkM9Xr1cvUd9VkNFw08jT6NF454mXpOhmai5V7NPc15LWytca6tWp9aUtpy2l3audov2Ax2yjoPOGp0GnVu6GF2GbrLuPt0berCehV6iXo3edX1Y31Kfq79Pf9AAbWBtwDNoMBgxJBk6GWYathiOGdGMfI3yjTqNnhtrGEcZ7zLuM/5oYmGSYtJoct9UxtTbNN+02/R3Mz0zllmN2S1zsrm7+QbzLvMXy/SXcZbtX3bHgmLhZ7HVosfig6WVJd+y1XLaSsMq1qrWaoRBZQQwShiXrdHWztYbrE9Zv7WxtBHYHLf5zdbQNtn2iO3Ucu3lnOWNy8ft1OyYdvV2o/Z0+1j7A/ajDqoOTIcGh8eO6o5sxybHSSddpySno07PnU2c+c7tzvMuNi7rXM65Iq4erkWuA24ybqFu1W6P3NXcE9xb3Gc9LDzWepzzRHv6eO7yHPFS8mJ5NXvNelt5r/Pu9SH5BPtU+zz21fPl+3b7wX7efrv9HqzQXMFb0ekP/L38d/s/DNAOWBPwYyAmMCCwJvBJkGlQXlBfMCU4JvhI8OsQ55DSkPuhOqHC0J4wybDosOaw+XDX8LLw0QjjiHUR1yIVIrmRXVHYqLCopqi5lW4r96yciLaILoweXqW9KnvVldUKq1NWn46RjGHGnIhFx4bHHol9z/RnNjDn4rziauNmWS6svaxnbEd2OXuaY8cp40zG28WXxU8l2CXsTphOdEisSJzhunCruS+SPJPqkuaT/ZMPJX9KCU9pS8Wlxqae5Mnwknm9acpp2WmD6frphemja2zW7Fkzy/fhN2VAGasyugRU0c9Uv1BHuEU4lmmfWZP5Jiss60S2dDYvuz9HL2d7zmSue+63a1FrWWt78lTzNuWNrXNaV78eWh+3vmeD+oaCDRMbPTYe3kTYlLzpp3yT/LL8V5vDN3cXKBVsLBjf4rGlpVCikF84stV2a9021DbutoHt5turtn8sYhddLTYprih+X8IqufqN6TeV33zaEb9joNSydP9OzE7ezuFdDrsOl0mX5ZaN7/bb3VFOLy8qf7UnZs+VimUVdXsJe4V7Ryt9K7uqNKp2Vr2vTqy+XeNc01arWLu9dn4fe9/Qfsf9rXVKdcV17w5wD9yp96jvaNBqqDiIOZh58EljWGPft4xvm5sUmoqbPhziHRo9HHS4t9mqufmI4pHSFrhF2DJ9NProje9cv+tqNWytb6O1FR8Dx4THnn4f+/3wcZ/jPScYJ1p/0Pyhtp3SXtQBdeR0zHYmdo52RXYNnvQ+2dNt293+o9GPh06pnqo5LXu69AzhTMGZT2dzz86dSz83cz7h/HhPTM/9CxEXbvUG9g5c9Ll4+ZL7pQt9Tn1nL9tdPnXF5srJq4yrndcsr3X0W/S3/2TxU/uA5UDHdavrXTesb3QPLh88M+QwdP6m681Lt7xuXbu94vbgcOjwnZHokdE77DtTd1PuvriXeW/h/sYH6AdFD6UeVjxSfNTws+7PbaOWo6fHXMf6Hwc/vj/OGn/2S8Yv7ycKnpCfVEyqTDZPmU2dmnafvvF05dOJZ+nPFmYKf5X+tfa5zvMffnP8rX82YnbiBf/Fp99LXsq/PPRq2aueuYC5R69TXy/MF72Rf3P4LeNt37vwd5MLWe+x7ys/6H7o/ujz8cGn1E+f/gUDmPP8usTo0wAAAAlwSFlzAAAOxAAADsQBlSsOGwAAAG5JREFUOE+VjMENwDAIA5OhOkX3n4eqSK4cakfhEeQ7E0ZE5JvXHe8Dn7rWsnKtZTD79oGa7bJyKttl5cDsbcEerNwnIWpmVk5+4sys3CJrWVk5W4CdB28PuMycQxW7zJxDFWDnwfbAqWst/12MB+3XXGPkZTU+AAAAAElFTkSuQmCCRPC or DCOMGE.DFInheritedfalseAnyAnyfalse + A representation of an (Advanced) Local Procedure Call data flow. + falseSE.DF.TMCore.ALPCBefore labeliVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGOfPtRkwAAACBjSFJNAACHDwAAjA8AAP1SAACBQAAAfXkAAOmLAAA85QAAGcxzPIV3AAAKOWlDQ1BQaG90b3Nob3AgSUNDIHByb2ZpbGUAAEjHnZZ3VFTXFofPvXd6oc0wAlKG3rvAANJ7k15FYZgZYCgDDjM0sSGiAhFFRJoiSFDEgNFQJFZEsRAUVLAHJAgoMRhFVCxvRtaLrqy89/Ly++Osb+2z97n77L3PWhcAkqcvl5cGSwGQyhPwgzyc6RGRUXTsAIABHmCAKQBMVka6X7B7CBDJy82FniFyAl8EAfB6WLwCcNPQM4BOB/+fpFnpfIHomAARm7M5GSwRF4g4JUuQLrbPipgalyxmGCVmvihBEcuJOWGRDT77LLKjmNmpPLaIxTmns1PZYu4V8bZMIUfEiK+ICzO5nCwR3xKxRoowlSviN+LYVA4zAwAUSWwXcFiJIjYRMYkfEuQi4uUA4EgJX3HcVyzgZAvEl3JJS8/hcxMSBXQdli7d1NqaQffkZKVwBALDACYrmcln013SUtOZvBwAFu/8WTLi2tJFRbY0tba0NDQzMv2qUP91829K3NtFehn4uWcQrf+L7a/80hoAYMyJarPziy2uCoDOLQDI3fti0zgAgKSobx3Xv7oPTTwviQJBuo2xcVZWlhGXwzISF/QP/U+Hv6GvvmckPu6P8tBdOfFMYYqALq4bKy0lTcinZ6QzWRy64Z+H+B8H/nUeBkGceA6fwxNFhImmjMtLELWbx+YKuGk8Opf3n5r4D8P+pMW5FonS+BFQY4yA1HUqQH7tBygKESDR+8Vd/6NvvvgwIH554SqTi3P/7zf9Z8Gl4iWDm/A5ziUohM4S8jMX98TPEqABAUgCKpAHykAd6ABDYAasgC1wBG7AG/iDEBAJVgMWSASpgA+yQB7YBApBMdgJ9oBqUAcaQTNoBcdBJzgFzoNL4Bq4AW6D+2AUTIBnYBa8BgsQBGEhMkSB5CEVSBPSh8wgBmQPuUG+UBAUCcVCCRAPEkJ50GaoGCqDqqF6qBn6HjoJnYeuQIPQXWgMmoZ+h97BCEyCqbASrAUbwwzYCfaBQ+BVcAK8Bs6FC+AdcCXcAB+FO+Dz8DX4NjwKP4PnEIAQERqiihgiDMQF8UeikHiEj6xHipAKpAFpRbqRPuQmMorMIG9RGBQFRUcZomxRnqhQFAu1BrUeVYKqRh1GdaB6UTdRY6hZ1Ec0Ga2I1kfboL3QEegEdBa6EF2BbkK3oy+ib6Mn0K8xGAwNo42xwnhiIjFJmLWYEsw+TBvmHGYQM46Zw2Kx8lh9rB3WH8vECrCF2CrsUexZ7BB2AvsGR8Sp4Mxw7rgoHA+Xj6vAHcGdwQ3hJnELeCm8Jt4G749n43PwpfhGfDf+On4Cv0CQJmgT7AghhCTCJkIloZVwkfCA8JJIJKoRrYmBRC5xI7GSeIx4mThGfEuSIemRXEjRJCFpB+kQ6RzpLuklmUzWIjuSo8gC8g5yM/kC+RH5jQRFwkjCS4ItsUGiRqJDYkjiuSReUlPSSXK1ZK5kheQJyeuSM1J4KS0pFymm1HqpGqmTUiNSc9IUaVNpf+lU6RLpI9JXpKdksDJaMm4ybJkCmYMyF2TGKQhFneJCYVE2UxopFykTVAxVm+pFTaIWU7+jDlBnZWVkl8mGyWbL1sielh2lITQtmhcthVZKO04bpr1borTEaQlnyfYlrUuGlszLLZVzlOPIFcm1yd2WeydPl3eTT5bfJd8p/1ABpaCnEKiQpbBf4aLCzFLqUtulrKVFS48vvacIK+opBimuVTyo2K84p6Ss5KGUrlSldEFpRpmm7KicpFyufEZ5WoWiYq/CVSlXOavylC5Ld6Kn0CvpvfRZVUVVT1Whar3qgOqCmrZaqFq+WpvaQ3WCOkM9Xr1cvUd9VkNFw08jT6NF454mXpOhmai5V7NPc15LWytca6tWp9aUtpy2l3audov2Ax2yjoPOGp0GnVu6GF2GbrLuPt0berCehV6iXo3edX1Y31Kfq79Pf9AAbWBtwDNoMBgxJBk6GWYathiOGdGMfI3yjTqNnhtrGEcZ7zLuM/5oYmGSYtJoct9UxtTbNN+02/R3Mz0zllmN2S1zsrm7+QbzLvMXy/SXcZbtX3bHgmLhZ7HVosfig6WVJd+y1XLaSsMq1qrWaoRBZQQwShiXrdHWztYbrE9Zv7WxtBHYHLf5zdbQNtn2iO3Ucu3lnOWNy8ft1OyYdvV2o/Z0+1j7A/ajDqoOTIcGh8eO6o5sxybHSSddpySno07PnU2c+c7tzvMuNi7rXM65Iq4erkWuA24ybqFu1W6P3NXcE9xb3Gc9LDzWepzzRHv6eO7yHPFS8mJ5NXvNelt5r/Pu9SH5BPtU+zz21fPl+3b7wX7efrv9HqzQXMFb0ekP/L38d/s/DNAOWBPwYyAmMCCwJvBJkGlQXlBfMCU4JvhI8OsQ55DSkPuhOqHC0J4wybDosOaw+XDX8LLw0QjjiHUR1yIVIrmRXVHYqLCopqi5lW4r96yciLaILoweXqW9KnvVldUKq1NWn46RjGHGnIhFx4bHHol9z/RnNjDn4rziauNmWS6svaxnbEd2OXuaY8cp40zG28WXxU8l2CXsTphOdEisSJzhunCruS+SPJPqkuaT/ZMPJX9KCU9pS8Wlxqae5Mnwknm9acpp2WmD6frphemja2zW7Fkzy/fhN2VAGasyugRU0c9Uv1BHuEU4lmmfWZP5Jiss60S2dDYvuz9HL2d7zmSue+63a1FrWWt78lTzNuWNrXNaV78eWh+3vmeD+oaCDRMbPTYe3kTYlLzpp3yT/LL8V5vDN3cXKBVsLBjf4rGlpVCikF84stV2a9021DbutoHt5turtn8sYhddLTYprih+X8IqufqN6TeV33zaEb9joNSydP9OzE7ezuFdDrsOl0mX5ZaN7/bb3VFOLy8qf7UnZs+VimUVdXsJe4V7Ryt9K7uqNKp2Vr2vTqy+XeNc01arWLu9dn4fe9/Qfsf9rXVKdcV17w5wD9yp96jvaNBqqDiIOZh58EljWGPft4xvm5sUmoqbPhziHRo9HHS4t9mqufmI4pHSFrhF2DJ9NProje9cv+tqNWytb6O1FR8Dx4THnn4f+/3wcZ/jPScYJ1p/0Pyhtp3SXtQBdeR0zHYmdo52RXYNnvQ+2dNt293+o9GPh06pnqo5LXu69AzhTMGZT2dzz86dSz83cz7h/HhPTM/9CxEXbvUG9g5c9Ll4+ZL7pQt9Tn1nL9tdPnXF5srJq4yrndcsr3X0W/S3/2TxU/uA5UDHdavrXTesb3QPLh88M+QwdP6m681Lt7xuXbu94vbgcOjwnZHokdE77DtTd1PuvriXeW/h/sYH6AdFD6UeVjxSfNTws+7PbaOWo6fHXMf6Hwc/vj/OGn/2S8Yv7ycKnpCfVEyqTDZPmU2dmnafvvF05dOJZ+nPFmYKf5X+tfa5zvMffnP8rX82YnbiBf/Fp99LXsq/PPRq2aueuYC5R69TXy/MF72Rf3P4LeNt37vwd5MLWe+x7ys/6H7o/ujz8cGn1E+f/gUDmPP8usTo0wAAAAlwSFlzAAAOxAAADsQBlSsOGwAAAEtJREFUOE9j+P//P1bMaOr9Hx2jqwFhDAEYHngDYBiXRhjGKoiMR5IBIIWkYmwGgGh0jFN8OBkA4qBhbGJYxbEagMNQrOIUGuD9HwBIkRfD8QF9EgAAAABJRU5ErkJggg==ALPCGE.DFInheritedfalseAnyAnyfalse + User Data Protocol Transport. + falseSE.DF.TMCore.UDPBefore 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UDPGE.DFInheritedfalseAnyAnyfalse + An interface for an application to communicate to a device driver. + falseSE.DF.TMCore.IOCTLBefore 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IOCTL InterfaceGE.DFInheritedfalseAnyAnyfalse + An arc representation of an Internet trust boundary. + falseSE.TB.L.TMCore.InternetBefore labeliVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAZdEVYdFNvZnR3YXJlAEFkb2JlIEltYWdlUmVhZHlxyWU8AAABX0lEQVQ4T2NgNPXGh/mhGJscGCNzQArtgVgfxmcy87kAwlA5ZLVwDGOAFQPp/1Dcj8zHZwiY4LUPdgLSMM0YmM8+5JaAY5gRkI3dAJuUUlsgjVUzCM/ZuDPg////vEA2dgNAkqpBKTuBbKwGRNV0iQNpmCZQGMG9AxPk57IJvA6ksRrAYu67EEjLA7E+s7nPReQwAWtGC0CiMMwQkPNZ5H0TtqArIIRBAWueUCgM9gLQEG1QGHDbBr1YuftQDJDvapFYtAhdEwwDY+TO8cvXXUCWw8IAbMjCrXtDgDQHlK8E04CO1YPTVoA0A9nwQIQZAtYMxaBAw2oAFINSLaoBSFgfGEgPgDQ2jWAs5hZVCaSxGwB0Ca+iX9I2IBusGORn3YistTA+q4Xf59KJcy1BarEaAMJAQ8ABixRg6omN/fWgwF26Y38EzLsghfiwNhBbADELlC8KxEpAzAHh/2cAANCSU7ngF2KpAAAAAElFTkSuQmCCInternet BoundaryGE.TB.LInheritedfalseAnyAnyfalse + An arc representation of a machine trust boundary. + falseSE.TB.L.TMCore.MachineBefore labeliVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAZdEVYdFNvZnR3YXJlAEFkb2JlIEltYWdlUmVhZHlxyWU8AAABX0lEQVQ4T2NgNPXGh/mhGJscGCNzQArtgVgfxmcy87kAwlA5ZLVwDGOAFQPp/1Dcj8zHZwiY4LUPdgLSMM0YmM8+5JaAY5gRkI3dAJuUUlsgjVUzCM/ZuDPg////vEA2dgNAkqpBKTuBbKwGRNV0iQNpmCZQGMG9AxPk57IJvA6ksRrAYu67EEjLA7E+s7nPReQwAWtGC0CiMMwQkPNZ5H0TtqArIIRBAWueUCgM9gLQEG1QGHDbBr1YuftQDJDvapFYtAhdEwwDY+TO8cvXXUCWw8IAbMjCrXtDgDQHlK8E04CO1YPTVoA0A9nwQIQZAtYMxaBAw2oAFINSLaoBSFgfGEgPgDQ2jWAs5hZVCaSxGwB0Ca+iX9I2IBusGORn3YistTA+q4Xf59KJcy1BarEaAMJAQ8ABixRg6omN/fWgwF26Y38EzLsghfiwNhBbADELlC8KxEpAzAHh/2cAANCSU7ngF2KpAAAAAElFTkSuQmCCMachine Trust BoundaryGE.TB.LInheritedfalseAnyAnyfalse + A border representation of user-model / kernel-mode separation. + falseSE.TB.L.TMCore.KernelBefore labeliVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAZdEVYdFNvZnR3YXJlAEFkb2JlIEltYWdlUmVhZHlxyWU8AAABX0lEQVQ4T2NgNPXGh/mhGJscGCNzQArtgVgfxmcy87kAwlA5ZLVwDGOAFQPp/1Dcj8zHZwiY4LUPdgLSMM0YmM8+5JaAY5gRkI3dAJuUUlsgjVUzCM/ZuDPg////vEA2dgNAkqpBKTuBbKwGRNV0iQNpmCZQGMG9AxPk57IJvA6ksRrAYu67EEjLA7E+s7nPReQwAWtGC0CiMMwQkPNZ5H0TtqArIIRBAWueUCgM9gLQEG1QGHDbBr1YuftQDJDvapFYtAhdEwwDY+TO8cvXXUCWw8IAbMjCrXtDgDQHlK8E04CO1YPTVoA0A9nwQIQZAtYMxaBAw2oAFINSLaoBSFgfGEgPgDQ2jWAs5hZVCaSxGwB0Ca+iX9I2IBusGORn3YistTA+q4Xf59KJcy1BarEaAMJAQ8ABixRg6omN/fWgwF26Y38EzLsghfiwNhBbADELlC8KxEpAzAHh/2cAANCSU7ngF2KpAAAAAElFTkSuQmCCUser mode or Kernel mode BoundaryGE.TB.LInheritedfalseAnyAnyfalse + A border representation for a Window Store AppContainer boundary. + falseSE.TB.L.TMCore.AppContainerBefore labeliVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAZdEVYdFNvZnR3YXJlAEFkb2JlIEltYWdlUmVhZHlxyWU8AAABX0lEQVQ4T2NgNPXGh/mhGJscGCNzQArtgVgfxmcy87kAwlA5ZLVwDGOAFQPp/1Dcj8zHZwiY4LUPdgLSMM0YmM8+5JaAY5gRkI3dAJuUUlsgjVUzCM/ZuDPg////vEA2dgNAkqpBKTuBbKwGRNV0iQNpmCZQGMG9AxPk57IJvA6ksRrAYu67EEjLA7E+s7nPReQwAWtGC0CiMMwQkPNZ5H0TtqArIIRBAWueUCgM9gLQEG1QGHDbBr1YuftQDJDvapFYtAhdEwwDY+TO8cvXXUCWw8IAbMjCrXtDgDQHlK8E04CO1YPTVoA0A9nwQIQZAtYMxaBAw2oAFINSLaoBSFgfGEgPgDQ2jWAs5hZVCaSxGwB0Ca+iX9I2IBusGORn3YistTA+q4Xf59KJcy1BarEaAMJAQ8ABixRg6omN/fWgwF26Y38EzLsghfiwNhBbADELlC8KxEpAzAHh/2cAANCSU7ngF2KpAAAAAElFTkSuQmCCAppContainer BoundaryGE.TB.LInheritedfalseAnyAnyfalse + A border representation of a corporate network trust boundary. + falseSE.TB.B.TMCore.CorpNetBefore labeliVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAOxAAADsQBlSsOGwAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAABGSURBVDhPY/hPIWBQ9Ev6z2jqDccPnr0ESxArzoDMAeEDZy+DFRIrDjeAVDCcDIDyyQajgTioAhGEQekdHx+bGIUGeP8HAJ4fIfJijo6MAAAAAElFTkSuQmCCCorpNet Trust BoundaryGE.TB.BBorderBoundaryfalseAnyAnyfalse + A border representation of a sandbox trust boundary. + falseSE.TB.B.TMCore.SandboxBefore labeliVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAOxAAADsQBlSsOGwAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAABGSURBVDhPY/hPIWBQ9Ev6z2jqDccPnr0ESxArzoDMAeEDZy+DFRIrDjeAVDCcDIDyyQajgTioAhGEQekdHx+bGIUGeP8HAJ4fIfJijo6MAAAAAElFTkSuQmCCSandbox Trust Boundary BorderGE.TB.BBorderBoundaryfalseAnyAnyfalsefalseNoYesLow Integrity Level SandboxVirtualDynamicIntegrityLevelListfalseNoYesApp Container SandboxVirtualDynamicAppContainerListfalseNoYesJavaScript SandboxVirtualDynamicJavaScriptListfalseNoYesFlash SandboxVirtualDynamicFlashList + Describes the types of trust boundaries implemented by Internet Explorer. + falseSE.TB.B.TMCore.IEBBefore labeliVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAOxAAADsQBlSsOGwAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAABGSURBVDhPY/hPIWBQ9Ev6z2jqDccPnr0ESxArzoDMAeEDZy+DFRIrDjeAVDCcDIDyyQajgTioAhGEQekdHx+bGIUGeP8HAJ4fIfJijo6MAAAAAElFTkSuQmCCInternet Explorer BoundariesGE.TB.BBorderBoundaryfalseAnyAnyfalsefalseNoYesChrome JavaScript SandboxVirtualDynamicChromeJavaListfalseNoYesChrome SandboxVirtualDynamicChromeListfalseNoYesFirefox JavaScript SandboxVirtualDynamicFirefoxJavaList + Describes the types of trust boundaries implemented by Google Chrome and Firefox. + falseSE.TB.B.TMCore.NonIEBBefore labeliVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAOxAAADsQBlSsOGwAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAABGSURBVDhPY/hPIWBQ9Ev6z2jqDccPnr0ESxArzoDMAeEDZy+DFRIrDjeAVDCcDIDyyQajgTioAhGEQekdHx+bGIUGeP8HAJ4fIfJijo6MAAAAAElFTkSuQmCCOther Browsers BoundariesGE.TB.BBorderBoundaryfalseAnyAnyfalseSSpoofingSpoofing is when a process or entity is something other than its claimed identity. Examples include substituting a process, a file, website or a network address.falseTTamperingTampering 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 processes.falseRRepudiationRepudiation threats involve an adversary denying that something happened.falseIInformation DisclosureInformation disclosure happens when the information can be read by an unauthorized party.falseDDenial Of ServiceDenial of Service happens when the process or a datastore is not able to service incoming requests or perform up to spec.falseEElevation Of PrivilegeA user subject gains increased capability or privilege by taking advantage of an implementation bug.falseAAbuseAbuse is when a legitimate user violates the terms of use for the system without violating a system security policy.truetrueTitlefalseac0f9ea8-3b39-4ce9-bac2-6787124d7b480UserThreatCategoryfalse0UserThreatShortDescriptiontrueSpoofing is when a process or entity is something other than its claimed identity. Examples include substituting a process, a file, website or a network address.Tampering 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 processes.Repudiation threats involve an adversary denying that something happened.Information disclosure happens when the information can be read by an unauthorized party.Denial of Service happens when the process or a datastore is not able to service incoming requests or perform up to spec.A user subject gains increased capability or privilege by taking advantage of an implementation bug.Abuse is when a legitimate user violates the terms of use for the system without violating a system security policy.5d3b996b-aed5-4d95-8cf6-617bb67bf0421UserThreatDescriptionfalsecf377f97-9dea-42d6-ae63-b097c4a8ec4d0StateInformationfalse0406a684-e06e-4643-ba21-0f63104d91310InteractionStringfalsed64f8926-f09d-4d67-a86f-fb4ad50364510PriorityfalseHighMediumLowbc9c6e2a-15d0-4863-9cac-589e51e4ca1e1falseSThreat was migrated from V3.source is 'ROOT'SUUserThreatShortDescriptiontrueSpoofing is when a process or entity is something other than its claimed identity. Examples include substituting a process, a file, website or a network address.5d3b996b-aed5-4d95-8cf6-617bb67bf0421UserThreatDescriptionfalseThreat was migrated from V3.cf377f97-9dea-42d6-ae63-b097c4a8ec4d0Priorityfalsebc9c6e2a-15d0-4863-9cac-589e51e4ca1e1Spoofing (v3)falseS{source.Name} may be spoofed by an attacker and this may lead to unauthorized access to {target.Name}. Consider using a standard authentication mechanism to identify the source process.flow.authenticatesSource is 'Yes' or source.implementsAuthenticationScheme is 'Yes'source is 'GE.P' and (target is 'GE.P' or target is 'GE.DS') and (flow crosses 'GE.TB.L' or flow crosses 'GE.TB.B')S1UserThreatShortDescriptiontrueSpoofing is when a process or entity is something other than its claimed identity. Examples include substituting a process, a file, website or a network address.5d3b996b-aed5-4d95-8cf6-617bb67bf0421UserThreatDescriptionfalse{source.Name} may be spoofed by an attacker and this may lead to unauthorized access to {target.Name}. Consider using a standard authentication mechanism to identify the source process.cf377f97-9dea-42d6-ae63-b097c4a8ec4d0Priorityfalsebc9c6e2a-15d0-4863-9cac-589e51e4ca1e1Spoofing the {source.Name} ProcessfalseS{target.Name} may be spoofed by an attacker and this may lead to information disclosure by {source.Name}. Consider using a standard authentication mechanism to identify the destination process.flow.authenticatesDestination is 'Yes'(source is 'GE.P' or source is 'GE.EI' or source is 'GE.DS') and target is 'GE.P' and (flow crosses 'GE.TB.L' or flow crosses 'GE.TB.B')S2UserThreatShortDescriptiontrueSpoofing is when a process or entity is something other than its claimed identity. Examples include substituting a process, a file, website or a network address.5d3b996b-aed5-4d95-8cf6-617bb67bf0421UserThreatDescriptionfalse{target.Name} may be spoofed by an attacker and this may lead to information disclosure by {source.Name}. Consider using a standard authentication mechanism to identify the destination process.cf377f97-9dea-42d6-ae63-b097c4a8ec4d0Priorityfalsebc9c6e2a-15d0-4863-9cac-589e51e4ca1e1Spoofing the {target.Name} ProcessfalseS{source.Name} may be spoofed by an attacker and this may lead to unauthorized access to {target.Name}. Consider using a standard authentication mechanism to identify the external entity.source.authenticatesItself is 'Yes' or flow.authenticatesSource is 'Yes'source is 'GE.EI' and target is 'GE.P'S3UserThreatShortDescriptiontrueSpoofing is when a process or entity is something other than its claimed identity. Examples include substituting a process, a file, website or a network address.5d3b996b-aed5-4d95-8cf6-617bb67bf0421UserThreatDescriptionfalse{source.Name} may be spoofed by an attacker and this may lead to unauthorized access to {target.Name}. Consider using a standard authentication mechanism to identify the external entity.cf377f97-9dea-42d6-ae63-b097c4a8ec4d0Priorityfalsebc9c6e2a-15d0-4863-9cac-589e51e4ca1e1Spoofing the {source.Name} External EntityfalseS{source.Name} may be spoofed by an attacker and this may lead to incorrect data delivered to {target.Name}. Consider using a standard authentication mechanism to identify the source data store.source is 'GE.DS'S7UserThreatShortDescriptiontrueSpoofing is when a process or entity is something other than its claimed identity. Examples include substituting a process, a file, website or a network address.5d3b996b-aed5-4d95-8cf6-617bb67bf0421UserThreatDescriptionfalse{source.Name} may be spoofed by an attacker and this may lead to incorrect data delivered to {target.Name}. Consider using a standard authentication mechanism to identify the source data store.cf377f97-9dea-42d6-ae63-b097c4a8ec4d0Priorityfalsebc9c6e2a-15d0-4863-9cac-589e51e4ca1e1Spoofing of Source Data Store {source.Name}falseS{target.Name} may be spoofed by an attacker and this may lead to data being written to the attacker's target instead of {target.Name}. Consider using a standard authentication mechanism to identify the destination data store.target is 'GE.DS'S7.1UserThreatShortDescriptiontrueSpoofing is when a process or entity is something other than its claimed identity. Examples include substituting a process, a file, website or a network address.5d3b996b-aed5-4d95-8cf6-617bb67bf0421UserThreatDescriptionfalse{target.Name} may be spoofed by an attacker and this may lead to data being written to the attacker's target instead of {target.Name}. Consider using a standard authentication mechanism to identify the destination data store.cf377f97-9dea-42d6-ae63-b097c4a8ec4d0Priorityfalsebc9c6e2a-15d0-4863-9cac-589e51e4ca1e1Spoofing of Destination Data Store {target.Name}falseS{target.Name} may be spoofed by an attacker and this may lead to data being sent to the attacker's target instead of {target.Name}. Consider using a standard authentication mechanism to identify the external entity.source is 'GE.P' and target is 'GE.EI' and (flow crosses 'GE.TB.L' or flow crosses 'GE.TB.B')S8UserThreatShortDescriptiontrueSpoofing is when a process or entity is something other than its claimed identity. Examples include substituting a process, a file, website or a network address.5d3b996b-aed5-4d95-8cf6-617bb67bf0421UserThreatDescriptionfalse{target.Name} may be spoofed by an attacker and this may lead to data being sent to the attacker's target instead of {target.Name}. Consider using a standard authentication mechanism to identify the external entity.cf377f97-9dea-42d6-ae63-b097c4a8ec4d0Priorityfalsebc9c6e2a-15d0-4863-9cac-589e51e4ca1e1Spoofing of the {target.Name} External Destination EntityfalseTThreat was migrated from V3.source is 'ROOT'TUUserThreatShortDescriptiontrueTampering 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 processes.5d3b996b-aed5-4d95-8cf6-617bb67bf0421UserThreatDescriptionfalseThreat was migrated from V3.cf377f97-9dea-42d6-ae63-b097c4a8ec4d0Priorityfalsebc9c6e2a-15d0-4863-9cac-589e51e4ca1e1Tampering (v3)falseTData flowing across {flow.Name} may be tampered with by an attacker. This may lead to a denial of service attack against {target.Name} or an elevation of privilege attack against {target.Name} or an information disclosure by {target.Name}. Failure to verify that input is as expected is a root cause of a very large number of exploitable issues. Consider all paths and the way they handle data. Verify that all input is verified for correctness using an approved list input validation approach.(flow.providesConfidentiality is 'Yes' and flow.providesIntegrity is 'Yes')(source is 'GE.P' or source is 'GE.EI') and target is 'GE.P' and (flow crosses 'GE.TB.L' or flow crosses 'GE.TB.B')T1UserThreatShortDescriptiontrueTampering 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 processes.5d3b996b-aed5-4d95-8cf6-617bb67bf0421UserThreatDescriptionfalseData flowing across {flow.Name} may be tampered with by an attacker. This may lead to a denial of service attack against {target.Name} or an elevation of privilege attack against {target.Name} or an information disclosure by {target.Name}. Failure to verify that input is as expected is a root cause of a very large number of exploitable issues. Consider all paths and the way they handle data. Verify that all input is verified for correctness using an approved list input validation approach.cf377f97-9dea-42d6-ae63-b097c4a8ec4d0Priorityfalsebc9c6e2a-15d0-4863-9cac-589e51e4ca1e1Potential Lack of Input Validation for {target.Name}falseTIf {source.Name} is given access to memory, such as shared memory or pointers, or is given the ability to control what {target.Name} executes (for example, passing back a function pointer.), then {source.Name} can tamper with {target.Name}. Consider if the function could work with less access to memory, such as passing data rather than pointers. Copy in data provided, and then validate it.source is 'GE.P' and target is 'GE.P' and target.codeType is 'Unmanaged'T2UserThreatShortDescriptiontrueTampering 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 processes.5d3b996b-aed5-4d95-8cf6-617bb67bf0421UserThreatDescriptionfalseIf {source.Name} is given access to memory, such as shared memory or pointers, or is given the ability to control what {target.Name} executes (for example, passing back a function pointer.), then {source.Name} can tamper with {target.Name}. Consider if the function could work with less access to memory, such as passing data rather than pointers. Copy in data provided, and then validate it.cf377f97-9dea-42d6-ae63-b097c4a8ec4d0Priorityfalsebc9c6e2a-15d0-4863-9cac-589e51e4ca1e1{source.Name} Process Memory TamperedfalseTPackets or messages without sequence numbers or timestamps can be captured and replayed in a wide variety of ways. Implement or utilize an existing communication protocol that supports anti-replay techniques (investigate sequence numbers before timers) and strong integrity.source is 'GE.P' and target is 'GE.P' and source.implementsCommunicationProtocol is 'Yes'T3UserThreatShortDescriptiontrueTampering 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 processes.5d3b996b-aed5-4d95-8cf6-617bb67bf0421UserThreatDescriptionfalsePackets or messages without sequence numbers or timestamps can be captured and replayed in a wide variety of ways. Implement or utilize an existing communication protocol that supports anti-replay techniques (investigate sequence numbers before timers) and strong integrity.cf377f97-9dea-42d6-ae63-b097c4a8ec4d0Priorityfalsebc9c6e2a-15d0-4863-9cac-589e51e4ca1e1Replay AttacksfalseTAttackers who can send a series of packets or messages may be able to overlap data. For example, packet 1 may be 100 bytes starting at offset 0. Packet 2 may be 100 bytes starting at offset 25. Packet 2 will overwrite 75 bytes of packet 1. Ensure you reassemble data before filtering it, and ensure you explicitly handle these sorts of cases.source is 'GE.P' and target is 'GE.P' and source.implementsCommunicationProtocol is 'Yes'T4UserThreatShortDescriptiontrueTampering 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 processes.5d3b996b-aed5-4d95-8cf6-617bb67bf0421UserThreatDescriptionfalseAttackers who can send a series of packets or messages may be able to overlap data. For example, packet 1 may be 100 bytes starting at offset 0. Packet 2 may be 100 bytes starting at offset 25. Packet 2 will overwrite 75 bytes of packet 1. Ensure you reassemble data before filtering it, and ensure you explicitly handle these sorts of cases.cf377f97-9dea-42d6-ae63-b097c4a8ec4d0Priorityfalsebc9c6e2a-15d0-4863-9cac-589e51e4ca1e1Collision AttacksfalseTLog readers can come under attack via log files. Consider ways to canonicalize data in all logs. Implement a single reader for the logs, if possible, in order to reduce attack surface area. Be sure to understand and document log file elements which come from untrusted sources.(source is 'GE.P' and target is 'GE.DS' and target.storesLogData is 'Yes') or (target is 'GE.P' and source is 'GE.DS' and source.storesLogData is 'Yes')T5UserThreatShortDescriptiontrueTampering 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 processes.5d3b996b-aed5-4d95-8cf6-617bb67bf0421UserThreatDescriptionfalseLog readers can come under attack via log files. Consider ways to canonicalize data in all logs. Implement a single reader for the logs, if possible, in order to reduce attack surface area. Be sure to understand and document log file elements which come from untrusted sources.cf377f97-9dea-42d6-ae63-b097c4a8ec4d0Priorityfalsebc9c6e2a-15d0-4863-9cac-589e51e4ca1e1Risks from LoggingfalseTAn attacker can read or modify data transmitted over an authenticated dataflow.(flow.providesConfidentiality is 'Yes' and flow.providesIntegrity is 'Yes')(flow.authenticatesSource is 'Yes' or flow.authenticatesDestination is 'Yes')T6UserThreatShortDescriptiontrueTampering 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 processes.5d3b996b-aed5-4d95-8cf6-617bb67bf0421UserThreatDescriptionfalseAn attacker can read or modify data transmitted over an authenticated dataflow.cf377f97-9dea-42d6-ae63-b097c4a8ec4d0Priorityfalsebc9c6e2a-15d0-4863-9cac-589e51e4ca1e1Authenticated Data Flow CompromisedfalseTSQL 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. Any procedure that constructs SQL statements should be reviewed for injection vulnerabilities because SQL Server will execute all syntactically valid queries that it receives. Even parameterized data can be manipulated by a skilled and determined attacker. + (target is 'SE.DS.TMCore.SQL' and source is 'GE.P') + T7UserThreatShortDescriptiontrueTampering 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 processes.5d3b996b-aed5-4d95-8cf6-617bb67bf0421UserThreatDescriptionfalseSQL 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. Any procedure that constructs SQL statements should be reviewed for injection vulnerabilities because SQL Server will execute all syntactically valid queries that it receives. Even parameterized data can be manipulated by a skilled and determined attacker.cf377f97-9dea-42d6-ae63-b097c4a8ec4d0Priorityfalsebc9c6e2a-15d0-4863-9cac-589e51e4ca1e1Potential SQL Injection Vulnerability for {target.Name}falseTSQL 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. Any procedure that constructs SQL statements should be reviewed for injection vulnerabilities because SQL Server will execute all syntactically valid queries that it receives. Even parameterized data can be manipulated by a skilled and determined attacker. + (target is 'SE.DS.TMCore.SQL' and source is 'GE.EI') + T8UserThreatShortDescriptiontrueTampering 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 processes.5d3b996b-aed5-4d95-8cf6-617bb67bf0421UserThreatDescriptionfalseSQL 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. Any procedure that constructs SQL statements should be reviewed for injection vulnerabilities because SQL Server will execute all syntactically valid queries that it receives. Even parameterized data can be manipulated by a skilled and determined attacker.cf377f97-9dea-42d6-ae63-b097c4a8ec4d0Priorityfalsebc9c6e2a-15d0-4863-9cac-589e51e4ca1e1Possible SQL Injection Vulnerability for {target.Name}falseTIf a dataflow contains XML, XML processing threats (DTD and XSLT code execution) may be exploited.(flow.XMLenc is 'Yes' and target is 'GE.P')T11UserThreatShortDescriptiontrueTampering 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 processes.5d3b996b-aed5-4d95-8cf6-617bb67bf0421UserThreatDescriptionfalseIf a dataflow contains XML, XML processing threats (DTD and XSLT code execution) may be exploited.cf377f97-9dea-42d6-ae63-b097c4a8ec4d0Priorityfalsebc9c6e2a-15d0-4863-9cac-589e51e4ca1e1XML DTD and XSLT ProcessingfalseTIf a dataflow contains JSON, JSON processing and hijacking threats may be exploited.((flow is 'SE.DF.TMCore.HTTP' or flow is 'SE.DF.TMCore.HTTPS') and flow.JSON is 'Yes' and target is 'GE.P')T12UserThreatShortDescriptiontrueTampering 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 processes.5d3b996b-aed5-4d95-8cf6-617bb67bf0421UserThreatDescriptionfalseIf a dataflow contains JSON, JSON processing and hijacking threats may be exploited.cf377f97-9dea-42d6-ae63-b097c4a8ec4d0Priorityfalsebc9c6e2a-15d0-4863-9cac-589e51e4ca1e1JavaScript Object Notation ProcessingfalseTThe web server '{target.Name}' could be a subject to a cross-site scripting attack because it does not sanitize untrusted input.(target.hasOutputSanitizers is 'Yes') and (target.hasInputSanitizers is 'Yes')(target is 'SE.P.TMCore.WebServer' or target is 'SE.P.TMCore.WebApp')T13.1UserThreatShortDescriptiontrueTampering 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 processes.5d3b996b-aed5-4d95-8cf6-617bb67bf0421UserThreatDescriptionfalseThe web server '{target.Name}' could be a subject to a cross-site scripting attack because it does not sanitize untrusted input.cf377f97-9dea-42d6-ae63-b097c4a8ec4d0Priorityfalsebc9c6e2a-15d0-4863-9cac-589e51e4ca1e1Cross Site ScriptingfalseTThe web server '{target.Name}' could be a subject to a persistent cross-site scripting attack because it does not sanitize data store '{source.Name}' inputs and output.(target.hasOutputSanitizers is 'Yes') and (target.hasInputSanitizers is 'Yes')(target is 'SE.P.TMCore.WebServer' or target is 'SE.P.TMCore.WebApp') and source is 'GE.DS'T13.2UserThreatShortDescriptiontrueTampering 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 processes.5d3b996b-aed5-4d95-8cf6-617bb67bf0421UserThreatDescriptionfalseThe web server '{target.Name}' could be a subject to a persistent cross-site scripting attack because it does not sanitize data store '{source.Name}' inputs and output.cf377f97-9dea-42d6-ae63-b097c4a8ec4d0Priorityfalsebc9c6e2a-15d0-4863-9cac-589e51e4ca1e1Persistent Cross Site ScriptingfalseTData flowing across {flow.Name} may be tampered with by an attacker. This may lead to corruption of {target.Name}. Ensure the integrity of the data flow to the data store.(source is 'GE.P' or source is 'GE.EI') and target is 'GE.DS' and (flow crosses 'GE.TB.L' or flow crosses 'GE.TB.B')T18UserThreatShortDescriptiontrueTampering 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 processes.5d3b996b-aed5-4d95-8cf6-617bb67bf0421UserThreatDescriptionfalseData flowing across {flow.Name} may be tampered with by an attacker. This may lead to corruption of {target.Name}. Ensure the integrity of the data flow to the data store.cf377f97-9dea-42d6-ae63-b097c4a8ec4d0Priorityfalsebc9c6e2a-15d0-4863-9cac-589e51e4ca1e1The {target.Name} Data Store Could Be CorruptedfalseRThreat was migrated from V3.source is 'ROOT'RUUserThreatShortDescriptiontrueRepudiation threats involve an adversary denying that something happened.5d3b996b-aed5-4d95-8cf6-617bb67bf0421UserThreatDescriptionfalseThreat was migrated from V3.cf377f97-9dea-42d6-ae63-b097c4a8ec4d0Priorityfalsebc9c6e2a-15d0-4863-9cac-589e51e4ca1e1Repudiation (v3)falseRIf you have trust levels, is anyone other outside of the highest trust level allowed to log? Letting everyone write to your logs can lead to repudiation problems. Only allow trusted code to log.(source is 'GE.P' or source is 'GE.EI') and (target is 'GE.DS') and (target.storesLogData is 'Yes')R1UserThreatShortDescriptiontrueRepudiation threats involve an adversary denying that something happened.5d3b996b-aed5-4d95-8cf6-617bb67bf0421UserThreatDescriptionfalseIf you have trust levels, is anyone other outside of the highest trust level allowed to log? Letting everyone write to your logs can lead to repudiation problems. Only allow trusted code to log.cf377f97-9dea-42d6-ae63-b097c4a8ec4d0Priorityfalsebc9c6e2a-15d0-4863-9cac-589e51e4ca1e1Lower Trusted Subject Updates LogsfalseRDo you accept logs from unknown or weakly authenticated users or systems? Identify and authenticate the source of the logs before accepting them.(source is 'GE.P' or source is 'GE.EI') and (target is 'GE.DS') and (target.storesLogData is 'Yes')R2UserThreatShortDescriptiontrueRepudiation threats involve an adversary denying that something happened.5d3b996b-aed5-4d95-8cf6-617bb67bf0421UserThreatDescriptionfalseDo you accept logs from unknown or weakly authenticated users or systems? Identify and authenticate the source of the logs before accepting them.cf377f97-9dea-42d6-ae63-b097c4a8ec4d0Priorityfalsebc9c6e2a-15d0-4863-9cac-589e51e4ca1e1Data Logs from an Unknown SourcefalseRDoes the log capture enough data to understand what happened in the past? Do your logs capture enough data to understand an incident after the fact? Is such capture lightweight enough to be left on all the time? Do you have enough data to deal with repudiation claims? Make sure you log sufficient and appropriate data to handle a repudiation claims. You might want to talk to an audit expert as well as a privacy expert about your choice of data.source is 'GE.P' and target is 'GE.DS' and target.storesLogData is 'Yes'R3UserThreatShortDescriptiontrueRepudiation threats involve an adversary denying that something happened.5d3b996b-aed5-4d95-8cf6-617bb67bf0421UserThreatDescriptionfalseDoes the log capture enough data to understand what happened in the past? Do your logs capture enough data to understand an incident after the fact? Is such capture lightweight enough to be left on all the time? Do you have enough data to deal with repudiation claims? Make sure you log sufficient and appropriate data to handle a repudiation claims. You might want to talk to an audit expert as well as a privacy expert about your choice of data.cf377f97-9dea-42d6-ae63-b097c4a8ec4d0Priorityfalsebc9c6e2a-15d0-4863-9cac-589e51e4ca1e1Insufficient AuditingfalseRConsider what happens when the audit mechanism comes under attack, including attempts to destroy the logs, or attack log analysis programs. Ensure access to the log is through a reference monitor, which controls read and write separately. Document what filters, if any, readers can rely on, or writers should expectsource is 'GE.P' and target is 'GE.DS' and target.storesLogData is 'Yes'R4UserThreatShortDescriptiontrueRepudiation threats involve an adversary denying that something happened.5d3b996b-aed5-4d95-8cf6-617bb67bf0421UserThreatDescriptionfalseConsider what happens when the audit mechanism comes under attack, including attempts to destroy the logs, or attack log analysis programs. Ensure access to the log is through a reference monitor, which controls read and write separately. Document what filters, if any, readers can rely on, or writers should expectcf377f97-9dea-42d6-ae63-b097c4a8ec4d0Priorityfalsebc9c6e2a-15d0-4863-9cac-589e51e4ca1e1Potential Weak Protections for Audit DatafalseR{target.Name} claims that it did not receive data from a source outside the trust boundary. Consider using logging or auditing to record the source, time, and summary of the received data.target is 'GE.P' and (flow crosses 'GE.TB.L' or flow crosses 'GE.TB.B')R6UserThreatShortDescriptiontrueRepudiation threats involve an adversary denying that something happened.5d3b996b-aed5-4d95-8cf6-617bb67bf0421UserThreatDescriptionfalse{target.Name} claims that it did not receive data from a source outside the trust boundary. Consider using logging or auditing to record the source, time, and summary of the received data.cf377f97-9dea-42d6-ae63-b097c4a8ec4d0Priorityfalsebc9c6e2a-15d0-4863-9cac-589e51e4ca1e1Potential Data Repudiation by {target.Name}falseR{target.Name} claims that it did not receive data from a process on the other side of the trust boundary. Consider using logging or auditing to record the source, time, and summary of the received data.target is 'GE.EI' and (flow crosses 'GE.TB.L' or flow crosses 'GE.TB.B')R7UserThreatShortDescriptiontrueRepudiation threats involve an adversary denying that something happened.5d3b996b-aed5-4d95-8cf6-617bb67bf0421UserThreatDescriptionfalse{target.Name} claims that it did not receive data from a process on the other side of the trust boundary. Consider using logging or auditing to record the source, time, and summary of the received data.cf377f97-9dea-42d6-ae63-b097c4a8ec4d0Priorityfalsebc9c6e2a-15d0-4863-9cac-589e51e4ca1e1External Entity {target.Name} Potentially Denies Receiving DatafalseR{target.Name} claims that it did not write data received from an entity on the other side of the trust boundary. Consider using logging or auditing to record the source, time, and summary of the received data.target is 'GE.DS' and (flow crosses 'GE.TB.L' or flow crosses 'GE.TB.B')R8UserThreatShortDescriptiontrueRepudiation threats involve an adversary denying that something happened.5d3b996b-aed5-4d95-8cf6-617bb67bf0421UserThreatDescriptionfalse{target.Name} claims that it did not write data received from an entity on the other side of the trust boundary. Consider using logging or auditing to record the source, time, and summary of the received data.cf377f97-9dea-42d6-ae63-b097c4a8ec4d0Priorityfalsebc9c6e2a-15d0-4863-9cac-589e51e4ca1e1Data Store Denies {target.Name} Potentially Writing DatafalseIThreat was migrated from V3.source is 'ROOT'IUUserThreatShortDescriptiontrueInformation disclosure happens when the information can be read by an unauthorized party.5d3b996b-aed5-4d95-8cf6-617bb67bf0421UserThreatDescriptionfalseThreat was migrated from V3.cf377f97-9dea-42d6-ae63-b097c4a8ec4d0Priorityfalsebc9c6e2a-15d0-4863-9cac-589e51e4ca1e1Information Disclosure (v3)falseICan you access {target.Name} and bypass the permissions for the object? For example by editing the files directly with a hex editor, or reaching it via filesharing? Ensure that your program is the only one that can access the data, and that all other subjects have to use your interface.source is 'GE.P' and target is 'GE.DS' and source.implementsCustomAuthorizationMechanism is 'Yes'I2UserThreatShortDescriptiontrueInformation disclosure happens when the information can be read by an unauthorized party.5d3b996b-aed5-4d95-8cf6-617bb67bf0421UserThreatDescriptionfalseCan you access {target.Name} and bypass the permissions for the object? For example by editing the files directly with a hex editor, or reaching it via filesharing? Ensure that your program is the only one that can access the data, and that all other subjects have to use your interface.cf377f97-9dea-42d6-ae63-b097c4a8ec4d0Priorityfalsebc9c6e2a-15d0-4863-9cac-589e51e4ca1e1Authorization BypassfalseIData flowing across {flow.Name} may be sniffed by an attacker. Depending on what type of data an attacker can read, it may be used to attack other parts of the system or simply be a disclosure of information leading to compliance violations. Consider encrypting the data flow.flow.providesConfidentiality is 'Yes'((source is 'GE.P' or source is 'GE.EI') and target is 'GE.P' and (flow crosses 'GE.TB.L' or flow crosses 'GE.TB.B')) or (source is 'GE.P' and target is 'GE.DS' and (flow crosses 'GE.TB.L' or flow crosses 'GE.TB.B'))I6UserThreatShortDescriptiontrueInformation disclosure happens when the information can be read by an unauthorized party.5d3b996b-aed5-4d95-8cf6-617bb67bf0421UserThreatDescriptionfalseData flowing across {flow.Name} may be sniffed by an attacker. Depending on what type of data an attacker can read, it may be used to attack other parts of the system or simply be a disclosure of information leading to compliance violations. Consider encrypting the data flow.cf377f97-9dea-42d6-ae63-b097c4a8ec4d0Priorityfalsebc9c6e2a-15d0-4863-9cac-589e51e4ca1e1Data Flow SniffingfalseIImproper data protection of {source.name} can allow an attacker to read information not intended for disclosure. Review authorization settings.source is 'GE.DS' and (target is 'GE.P' or target is 'GE.EI')I23UserThreatShortDescriptiontrueInformation disclosure happens when the information can be read by an unauthorized party.5d3b996b-aed5-4d95-8cf6-617bb67bf0421UserThreatDescriptionfalseImproper data protection of {source.name} can allow an attacker to read information not intended for disclosure. Review authorization settings.cf377f97-9dea-42d6-ae63-b097c4a8ec4d0Priorityfalsebc9c6e2a-15d0-4863-9cac-589e51e4ca1e1Weak Access Control for a ResourcefalseICredentials held at the server are often disclosed or tampered with and credentials stored on the client are often stolen. For server side, consider storing a salted hash of the credentials instead of storing the credentials themselves. If this is not possible due to business requirements, be sure to encrypt the credentials before storage, using an SDL-approved mechanism. For client side, if storing credentials is required, encrypt them and protect the data store in which they're storedsource is 'GE.P' and target is 'GE.DS' and target.storesCredentials is 'Yes'I24UserThreatShortDescriptiontrueInformation disclosure happens when the information can be read by an unauthorized party.5d3b996b-aed5-4d95-8cf6-617bb67bf0421UserThreatDescriptionfalseCredentials held at the server are often disclosed or tampered with and credentials stored on the client are often stolen. For server side, consider storing a salted hash of the credentials instead of storing the credentials themselves. If this is not possible due to business requirements, be sure to encrypt the credentials before storage, using an SDL-approved mechanism. For client side, if storing credentials is required, encrypt them and protect the data store in which they're storedcf377f97-9dea-42d6-ae63-b097c4a8ec4d0Priorityfalsebc9c6e2a-15d0-4863-9cac-589e51e4ca1e1Weak Credential StoragefalseICredentials on the wire are often subject to sniffing by an attacker. Are the credentials re-usable/re-playable? Are credentials included in a message? For example, sending a zip file with the password in the email. Use strong cryptography for the transmission of credentials. Use the OS libraries if at all possible, and consider cryptographic algorithm agility, rather than hardcoding a choice.flow is 'SE.DF.TMCore.HTTPS' or flow is 'SE.DF.TMCore.IPsec'source is 'GE.P' and (target is 'GE.P' or target is 'GE.DS') and (flow crosses 'SE.TB.L.TMCore.Machine')I25UserThreatShortDescriptiontrueInformation disclosure happens when the information can be read by an unauthorized party.5d3b996b-aed5-4d95-8cf6-617bb67bf0421UserThreatDescriptionfalseCredentials on the wire are often subject to sniffing by an attacker. Are the credentials re-usable/re-playable? Are credentials included in a message? For example, sending a zip file with the password in the email. Use strong cryptography for the transmission of credentials. Use the OS libraries if at all possible, and consider cryptographic algorithm agility, rather than hardcoding a choice.cf377f97-9dea-42d6-ae63-b097c4a8ec4d0Priorityfalsebc9c6e2a-15d0-4863-9cac-589e51e4ca1e1Weak Credential TransitfalseICustom authentication schemes are susceptible to common weaknesses such as weak credential change management, credential equivalence, easily guessable credentials, null credentials, downgrade authentication or a weak credential change management system. Consider the impact and potential mitigations for your custom authentication scheme.source is 'GE.P' and target is 'GE.P' and source.implementsAuthenticationScheme is 'Yes'I26UserThreatShortDescriptiontrueInformation disclosure happens when the information can be read by an unauthorized party.5d3b996b-aed5-4d95-8cf6-617bb67bf0421UserThreatDescriptionfalseCustom authentication schemes are susceptible to common weaknesses such as weak credential change management, credential equivalence, easily guessable credentials, null credentials, downgrade authentication or a weak credential change management system. Consider the impact and potential mitigations for your custom authentication scheme.cf377f97-9dea-42d6-ae63-b097c4a8ec4d0Priorityfalsebc9c6e2a-15d0-4863-9cac-589e51e4ca1e1Weak Authentication SchemefalseDThreat was migrated from V3.source is 'ROOT'DUUserThreatShortDescriptiontrueDenial of Service happens when the process or a datastore is not able to service incoming requests or perform up to spec.5d3b996b-aed5-4d95-8cf6-617bb67bf0421UserThreatDescriptionfalseThreat was migrated from V3.cf377f97-9dea-42d6-ae63-b097c4a8ec4d0Priorityfalsebc9c6e2a-15d0-4863-9cac-589e51e4ca1e1Denial Of Service (v3)falseDDoes {source.Name} or {target.Name} take explicit steps to control resource consumption? Resource consumption attacks can be hard to deal with, and there are times that it makes sense to let the OS do the job. Be careful that your resource requests don't deadlock, and that they do timeout.source is 'GE.P' and target is 'GE.DS'D2UserThreatShortDescriptiontrueDenial of Service happens when the process or a datastore is not able to service incoming requests or perform up to spec.5d3b996b-aed5-4d95-8cf6-617bb67bf0421UserThreatDescriptionfalseDoes {source.Name} or {target.Name} take explicit steps to control resource consumption? Resource consumption attacks can be hard to deal with, and there are times that it makes sense to let the OS do the job. Be careful that your resource requests don't deadlock, and that they do timeout.cf377f97-9dea-42d6-ae63-b097c4a8ec4d0Priorityfalsebc9c6e2a-15d0-4863-9cac-589e51e4ca1e1Potential Excessive Resource Consumption for {source.Name} or {target.Name}falseD{target.Name} crashes, halts, stops or runs slowly; in all cases violating an availability metric.target is 'GE.P' and (flow crosses 'GE.TB.L' or flow crosses 'GE.TB.B')D3UserThreatShortDescriptiontrueDenial of Service happens when the process or a datastore is not able to service incoming requests or perform up to spec.5d3b996b-aed5-4d95-8cf6-617bb67bf0421UserThreatDescriptionfalse{target.Name} crashes, halts, stops or runs slowly; in all cases violating an availability metric.cf377f97-9dea-42d6-ae63-b097c4a8ec4d0Priorityfalsebc9c6e2a-15d0-4863-9cac-589e51e4ca1e1Potential Process Crash or Stop for {target.Name}falseDAn external agent interrupts data flowing across a trust boundary in either direction.(flow crosses 'GE.TB.L' or flow crosses 'GE.TB.B')D4UserThreatShortDescriptiontrueDenial of Service happens when the process or a datastore is not able to service incoming requests or perform up to spec.5d3b996b-aed5-4d95-8cf6-617bb67bf0421UserThreatDescriptionfalseAn external agent interrupts data flowing across a trust boundary in either direction.cf377f97-9dea-42d6-ae63-b097c4a8ec4d0Priorityfalsebc9c6e2a-15d0-4863-9cac-589e51e4ca1e1Data Flow {flow.Name} Is Potentially InterruptedfalseDAn external agent prevents access to a data store on the other side of the trust boundary.(source is 'GE.DS' or target is 'GE.DS') and (flow crosses 'GE.TB.L' or flow crosses 'GE.TB.B')D5UserThreatShortDescriptiontrueDenial of Service happens when the process or a datastore is not able to service incoming requests or perform up to spec.5d3b996b-aed5-4d95-8cf6-617bb67bf0421UserThreatDescriptionfalseAn external agent prevents access to a data store on the other side of the trust boundary.cf377f97-9dea-42d6-ae63-b097c4a8ec4d0Priorityfalsebc9c6e2a-15d0-4863-9cac-589e51e4ca1e1Data Store InaccessiblefalseEThreat was migrated from V3.source is 'ROOT'EUUserThreatShortDescriptiontrueA user subject gains increased capability or privilege by taking advantage of an implementation bug.5d3b996b-aed5-4d95-8cf6-617bb67bf0421UserThreatDescriptionfalseThreat was migrated from V3.cf377f97-9dea-42d6-ae63-b097c4a8ec4d0Priorityfalsebc9c6e2a-15d0-4863-9cac-589e51e4ca1e1Elevation Of Privilege (v3)falseECommon SSO implementations such as OAUTH2 and OAUTH Wrap are vulnerable to MitM attacks.(target is 'SE.EI.TMCore.AuthProvider' and target.MS is 'Yes')target is 'SE.EI.TMCore.AuthProvider'E3UserThreatShortDescriptiontrueA user subject gains increased capability or privilege by taking advantage of an implementation bug.5d3b996b-aed5-4d95-8cf6-617bb67bf0421UserThreatDescriptionfalseCommon SSO implementations such as OAUTH2 and OAUTH Wrap are vulnerable to MitM attacks.cf377f97-9dea-42d6-ae63-b097c4a8ec4d0Priorityfalsebc9c6e2a-15d0-4863-9cac-589e51e4ca1e1Weakness in SSO AuthorizationfalseE{target.Name} may be able to impersonate the context of {source.Name} in order to gain additional privilege.(source is 'GE.EI' or source is 'GE.P') and target is 'GE.P'E5UserThreatShortDescriptiontrueA user subject gains increased capability or privilege by taking advantage of an implementation bug.5d3b996b-aed5-4d95-8cf6-617bb67bf0421UserThreatDescriptionfalse{target.Name} may be able to impersonate the context of {source.Name} in order to gain additional privilege.cf377f97-9dea-42d6-ae63-b097c4a8ec4d0Priorityfalsebc9c6e2a-15d0-4863-9cac-589e51e4ca1e1Elevation Using ImpersonationfalseE{source.Name} may be able to remotely execute code for {target.Name}.target is 'GE.P' and (flow crosses 'GE.TB.L' or flow crosses 'GE.TB.B')E6UserThreatShortDescriptiontrueA user subject gains increased capability or privilege by taking advantage of an implementation bug.5d3b996b-aed5-4d95-8cf6-617bb67bf0421UserThreatDescriptionfalse{source.Name} may be able to remotely execute code for {target.Name}.cf377f97-9dea-42d6-ae63-b097c4a8ec4d0Priorityfalsebc9c6e2a-15d0-4863-9cac-589e51e4ca1e1{target.Name} May be Subject to Elevation of Privilege Using Remote Code ExecutionfalseEAn attacker may pass data into {target.Name} in order to change the flow of program execution within {target.Name} to the attacker's choosing.target is 'GE.P' and (flow crosses 'GE.TB.L' or flow crosses 'GE.TB.B')E7UserThreatShortDescriptiontrueA user subject gains increased capability or privilege by taking advantage of an implementation bug.5d3b996b-aed5-4d95-8cf6-617bb67bf0421UserThreatDescriptionfalseAn attacker may pass data into {target.Name} in order to change the flow of program execution within {target.Name} to the attacker's choosing.cf377f97-9dea-42d6-ae63-b097c4a8ec4d0Priorityfalsebc9c6e2a-15d0-4863-9cac-589e51e4ca1e1Elevation by Changing the Execution Flow in {target.Name}falseECross-site request forgery (CSRF or XSRF) is a type of attack in which an attacker forces a user's browser to make a forged request to a vulnerable site by exploiting an existing trust relationship between the browser and the vulnerable web site. In a simple scenario, a user is logged in to web site A using a cookie as a credential. The other browses to web site B. Web site B returns a page with a hidden form that posts to web site A. Since the browser will carry the user's cookie to web site A, web site B now can take any action on web site A, for example, adding an admin to an account. The attack can be used to exploit any requests that the browser automatically authenticates, e.g. by session cookie, integrated authentication, IP whitelisting. The attack can be carried out in many ways such as by luring the victim to a site under control of the attacker, getting the user to click a link in a phishing email, or hacking a reputable web site that the victim will visit. The issue can only be resolved on the server side by requiring that all authenticated state-changing requests include an additional piece of secret payload (canary or CSRF token) which is known only to the legitimate web site and the browser and which is protected in transit through SSL/TLS. See the Forgery Protection property on the flow stencil for a list of mitigations.(source is 'SE.P.TMCore.OSProcess' or source is 'SE.P.TMCore.Thread' or source is 'SE.P.TMCore.KernelThread' or source is 'SE.P.TMCore.WinApp' or source is 'SE.P.TMCore.NetApp' or source is 'SE.P.TMCore.WebServer' or source is 'SE.P.TMCore.Win32Service' or source is 'SE.P.TMCore.WebSvc' or source is 'SE.P.TMCore.VM' or (source is 'SE.P.TMCore.Modern' and source.internetClientServer is 'No' and source.internetClient is 'No' ) or source is 'SE.EI.TMCore.AuthProvider' or source is 'SE.EI.TMCore.WebSvc' or source is 'SE.EI.TMCore.WebApp' or source is 'SE.EI.TMCore.Megasevrice' or source is 'SE.EI.TMCore.CRT' or source is 'SE.EI.TMCore.NFX' or source is 'SE.EI.TMCore.WinRT' ) or (target is 'SE.P.TMCore.ThickClient' or target is 'SE.P.TMCore.BrowserClient' or target is 'SE.P.TMCore.PlugIn' or target is 'SE.P.TMCore.Modern') or (flow crosses 'SE.TB.L.TMCore.Machine' or flow crosses 'SE.TB.L.TMCore.Kernel' or flow crosses 'SE.TB.L.TMCore.AppContainer' or flow crosses 'SE.TB.B.TMCore.CorpNet' or flow crosses 'SE.TB.B.TMCore.Sandbox')(source is 'GE.P' or source is 'GE.EI') and (target is 'GE.P' ) and (flow.authenticatesSource is 'Not Selected' or flow.authenticatesSource is 'Yes') and (flow.54851a3b-65da-4902-b4e0-94ef015be735 is 'None' or flow.54851a3b-65da-4902-b4e0-94ef015be735 is 'Not Selected' ) and (flow crosses 'GE.TB.L' or flow crosses 'GE.TB.B')8404dcf5-bdd8-4902-abc2-3b6c967b0261UserThreatShortDescriptiontrue5d3b996b-aed5-4d95-8cf6-617bb67bf0421UserThreatDescriptionfalseCross-site request forgery (CSRF or XSRF) is a type of attack in which an attacker forces a user's browser to make a forged request to a vulnerable site by exploiting an existing trust relationship between the browser and the vulnerable web site. In a simple scenario, a user is logged in to web site A using a cookie as a credential. The other browses to web site B. Web site B returns a page with a hidden form that posts to web site A. Since the browser will carry the user's cookie to web site A, web site B now can take any action on web site A, for example, adding an admin to an account. The attack can be used to exploit any requests that the browser automatically authenticates, e.g. by session cookie, integrated authentication, IP whitelisting. The attack can be carried out in many ways such as by luring the victim to a site under control of the attacker, getting the user to click a link in a phishing email, or hacking a reputable web site that the victim will visit. The issue can only be resolved on the server side by requiring that all authenticated state-changing requests include an additional piece of secret payload (canary or CSRF token) which is known only to the legitimate web site and the browser and which is protected in transit through SSL/TLS. See the Forgery Protection property on the flow stencil for a list of mitigations.cf377f97-9dea-42d6-ae63-b097c4a8ec4d0Priorityfalsebc9c6e2a-15d0-4863-9cac-589e51e4ca1e1Cross Site Request Forgery
\ No newline at end of file diff --git a/Deployment/AadAppManifest.json b/Deployment/AadAppManifest.json index e410284b3..93e41f831 100644 --- a/Deployment/AadAppManifest.json +++ b/Deployment/AadAppManifest.json @@ -1,31 +1,31 @@ [ - { - "resourceAppId": "00000003-0000-0000-c000-000000000000", - "resourceAccess": [ - { - "id": "5f8c59db-677d-491f-a6b8-5f174b11ec1d", - "type": "Scope" - }, - { - "id": "e1fe6dd8-ba31-4d61-89e7-88639da4683d", - "type": "Scope" - }, - { - "id": "88e58d74-d3df-44f3-ad47-e89edf4472e4", - "type": "Scope" - }, - { - "id": "5b567255-7703-4780-807c-7be8301ae99b", - "type": "Role" - }, - { - "id": "df021288-bdef-4463-88db-98f22de89214", - "type": "Role" - }, - { - "id": "74ef0291-ca83-4d02-8c7e-d2391e6a444f", - "type": "Role" - } - ] - } -] \ No newline at end of file + { + "resourceAppId": "00000003-0000-0000-c000-000000000000", + "resourceAccess": [ + { + "id": "bc024368-1153-4739-b217-4326f2e966d0", + "type": "Scope" + }, + { + "id": "e1fe6dd8-ba31-4d61-89e7-88639da4683d", + "type": "Scope" + }, + { + "id": "88e58d74-d3df-44f3-ad47-e89edf4472e4", + "type": "Scope" + }, + { + "id": "98830695-27a2-44f7-8c18-0c3ebc9698f6", + "type": "Role" + }, + { + "id": "df021288-bdef-4463-88db-98f22de89214", + "type": "Role" + }, + { + "id": "74ef0291-ca83-4d02-8c7e-d2391e6a444f", + "type": "Role" + } + ] + } +] diff --git a/Deployment/azuredeploy.json b/Deployment/azuredeploy.json index cbcde321b..4e55a329a 100644 --- a/Deployment/azuredeploy.json +++ b/Deployment/azuredeploy.json @@ -39,6 +39,21 @@ "description": "The client secret of the author bot Azure AD app." } }, + "graphAppId": { + "type": "string", + "minLength": 36, + "maxLength": 36, + "metadata": { + "description": "The client ID of the Microsoft Graph Azure AD app, e.g., 123e4567-e89b-12d3-a456-426655440000." + } + }, + "graphAppSecret": { + "type": "securestring", + "minLength": 1, + "metadata": { + "description": "The client secret of the Microsoft Graph Azure AD app." + } + }, "senderUPNList": { "type": "string", "minLength": 1, @@ -179,6 +194,62 @@ "description": "The branch of the GitHub repository to deploy." }, "defaultValue": "master" + }, + "serviceBusWebAppRoleNameGuid": { + "defaultValue": "958380b3-630d-4823-b933-f59d92cdcada", + "minLength": 1, + "type": "String", + "metadata": { + "description": "A GUID used to identify the role assignment. This is Default value." + } + }, + "serviceBusPrepFuncRoleNameGuid": { + "defaultValue": "ce6ca916-08e9-4639-bfbe-9d098baf42ca", + "minLength": 1, + "type": "String", + "metadata": { + "description": "A GUID used to identify the role assignment. This is Default value." + } + }, + "serviceBusSendFuncRoleNameGuid": { + "defaultValue": "960365a2-c7bf-4ff3-8887-efa86fe4a163", + "minLength": 1, + "type": "String", + "metadata": { + "description": "A GUID used to identify the role assignment. This is Default value." + } + }, + "serviceBusDataFuncRoleNameGuid": { + "defaultValue": "d42703bc-421d-4d98-bc4d-cd2bb16e5b0a", + "minLength": 1, + "type": "String", + "metadata": { + "description": "A GUID used to identify the role assignment. This is Default value." + } + }, + "storageAccountWebAppRoleNameGuid": { + "defaultValue": "edd0cc48-2cf7-490e-99e8-131311e42030", + "minLength": 1, + "type": "String", + "metadata": { + "description": "A GUID used to identify the role assignment. This is Default value." + } + }, + "storageAccountPrepFuncRoleNameGuid": { + "defaultValue": "9332a9e9-93f4-48d9-8121-d279f30a732e", + "minLength": 1, + "type": "String", + "metadata": { + "description": "A GUID used to identify the role assignment. This is Default value." + } + }, + "storageAccountDataFuncRoleNameGuid": { + "defaultValue": "5b67af51-4a98-47e1-9d22-745069f51a13", + "minLength": 1, + "type": "String", + "metadata": { + "description": "A GUID used to identify the role assignment. This is Default value." + } } }, "variables": { @@ -212,7 +283,24 @@ "ProactivelyInstallUserApp": "[parameters('ProactivelyInstallUserApp')]", "UserAppExternalId": "[parameters('UserAppExternalId')]", "i18n:DefaultCulture": "[parameters('DefaultCulture')]", - "i18n:SupportedCultures": "[parameters('SupportedCultures')]" + "i18n:SupportedCultures": "[parameters('SupportedCultures')]", + "AzureserviceBusDataOwner": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Authorization/roleDefinitions/', '090c5cfd-751d-490a-894a-3ce6f1109419')]", + "StorageBlobDataContributor": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Authorization/roleDefinitions/', 'ba92f5b4-2d11-453d-a403-e96b0029c9fe')]", + "keyvaultName": "[concat(variables('botAppName'), 'vault')]", + "keyVaultUrl": "[concat('https://',variables('keyvaultName'), '.vault.azure.net')]", + "subscriptionTenantId": "[subscription().tenantId]", + "StorageAccountSecretName": "[concat(variables('keyVaultName'), 'StorageAccountConnectionString')]", + "ServiceBusSecretName": "[concat(variables('keyVaultName'), 'ServiceBusConnectionString')]", + "AppInsightsSecretName": "[concat(variables('keyVaultName'),'AppInsightsKey')]", + "UserAppSecretName": "[concat(variables('keyVaultName'),'UserAppPassword')]", + "AuthorAppSecretName": "[concat(variables('keyVaultName'),'AuthorAppPassword')]", + "GraphAppSecretName": "[concat(variables('keyVaultName'),'GraphAppPassword')]", + "StorageAccountSecretResourceId": "[resourceId(resourceGroup().name, 'Microsoft.KeyVault/vaults/secrets', variables('keyVaultName'), variables('StorageAccountSecretName'))]", + "ServiceBusSecretResourceId": "[resourceId(resourceGroup().name, 'Microsoft.KeyVault/vaults/secrets', variables('keyVaultName'), variables('ServiceBusSecretName'))]", + "AppInsightsSecretResourceId": "[resourceId(resourceGroup().name, 'Microsoft.KeyVault/vaults/secrets', variables('keyVaultName'), variables('AppInsightsSecretName'))]", + "UserAppSecretResourceId": "[resourceId(resourceGroup().name, 'Microsoft.KeyVault/vaults/secrets', variables('keyVaultName'), variables('UserAppSecretName'))]", + "AuthorAppSecretResourceId": "[resourceId(resourceGroup().name, 'Microsoft.KeyVault/vaults/secrets', variables('keyVaultName'), variables('AuthorAppSecretName'))]", + "GraphAppSecretResourceId": "[resourceId(resourceGroup().name, 'Microsoft.KeyVault/vaults/secrets', variables('keyVaultName'), variables('GraphAppSecretName'))]" }, "resources": [ { @@ -229,6 +317,106 @@ "name": "Standard_LRS" } }, + { + "type": "Microsoft.ServiceBus/namespaces", + "apiVersion": "2017-04-01", + "name": "[variables('serviceBusNamespaceName')]", + "location": "[parameters('location')]", + "sku": { + "name": "Basic", + "tier": "Basic" + }, + "resources": [ + { + "type": "Queues", + "apiVersion": "2017-04-01", + "name": "[variables('serviceBusSendQueueName')]", + "dependsOn": [ + "[concat('Microsoft.ServiceBus/namespaces/', variables('serviceBusNamespaceName'))]" + ], + "properties": { + "lockDuration": "PT5M", + "maxSizeInMegabytes": 1024, + "requiresDuplicateDetection": false, + "requiresSession": false, + "defaultMessageTimeToLive": "P14D", + "deadLetteringOnMessageExpiration": false, + "enableBatchedOperations": true, + "duplicateDetectionHistoryTimeWindow": "PT10M", + "maxDeliveryCount": 10, + "status": "Active", + "enablePartitioning": false, + "enableExpress": false + } + }, + { + "type": "Queues", + "apiVersion": "2017-04-01", + "name": "[variables('serviceBusDataQueueName')]", + "dependsOn": [ + "[concat('Microsoft.ServiceBus/namespaces/', variables('serviceBusNamespaceName'))]" + ], + "properties": { + "lockDuration": "PT5M", + "maxSizeInMegabytes": 1024, + "requiresDuplicateDetection": false, + "requiresSession": false, + "defaultMessageTimeToLive": "P14D", + "deadLetteringOnMessageExpiration": false, + "enableBatchedOperations": true, + "duplicateDetectionHistoryTimeWindow": "PT10M", + "maxDeliveryCount": 10, + "status": "Active", + "enablePartitioning": false, + "enableExpress": false + } + }, + { + "type": "Queues", + "apiVersion": "2017-04-01", + "name": "[variables('serviceBusPrepareToSendQueueName')]", + "dependsOn": [ + "[concat('Microsoft.ServiceBus/namespaces/', variables('serviceBusNamespaceName'))]" + ], + "properties": { + "lockDuration": "PT5M", + "maxSizeInMegabytes": 1024, + "requiresDuplicateDetection": false, + "requiresSession": false, + "defaultMessageTimeToLive": "P14D", + "deadLetteringOnMessageExpiration": false, + "enableBatchedOperations": true, + "duplicateDetectionHistoryTimeWindow": "PT10M", + "maxDeliveryCount": 10, + "status": "Active", + "enablePartitioning": false, + "enableExpress": false + } + }, + { + "type": "Queues", + "apiVersion": "2017-04-01", + "name": "[variables('serviceBusExportQueueName')]", + "dependsOn": [ + "[concat('Microsoft.ServiceBus/namespaces/', variables('serviceBusNamespaceName'))]" + ], + "properties": { + "lockDuration": "PT5M", + "maxSizeInMegabytes": 1024, + "requiresDuplicateDetection": false, + "requiresSession": false, + "defaultMessageTimeToLive": "P14D", + "deadLetteringOnMessageExpiration": false, + "enableBatchedOperations": true, + "duplicateDetectionHistoryTimeWindow": "PT10M", + "maxDeliveryCount": 10, + "status": "Active", + "enablePartitioning": false, + "enableExpress": false + } + } + ] + }, { "type": "Microsoft.Web/serverfarms", "apiVersion": "2016-09-01", @@ -247,153 +435,6 @@ "capacity": 0 } }, - { - "apiVersion": "2016-08-01", - "type": "Microsoft.Web/sites", - "name": "[variables('botAppName')]", - "location": "[parameters('location')]", - "kind": "app", - "properties": { - "name": "[variables('botAppName')]", - "serverFarmId": "[resourceId('Microsoft.Web/serverfarms', variables('hostingPlanName'))]", - "enabled": true, - "reserved": false, - "clientAffinityEnabled": true, - "clientCertEnabled": false, - "hostNamesDisabled": false, - "containerSize": 0, - "dailyMemoryTimeQuota": 0, - "httpsOnly": true, - "siteConfig": { - "alwaysOn": "[not(variables('isSharedPlan'))]", - "appSettings": [ - { - "name": "PROJECT", - "value": "Source/CompanyCommunicator/Microsoft.Teams.Apps.CompanyCommunicator.csproj" - }, - { - "name": "SITE_ROLE", - "value": "app" - }, - { - "name": "i18n:DefaultCulture", - "value": "[variables('i18n:DefaultCulture')]" - }, - { - "name": "i18n:SupportedCultures", - "value": "[variables('i18n:SupportedCultures')]" - }, - { - "name": "ProactivelyInstallUserApp", - "value": "[variables('ProactivelyInstallUserApp')]" - }, - { - "name": "UserAppExternalId", - "value": "[variables('UserAppExternalId')]" - }, - { - "name": "AzureAd:TenantId", - "value": "[parameters('tenantId')]" - }, - { - "name": "AzureAd:ClientId", - "value": "[parameters('authorClientId')]" - }, - { - "name": "AzureAd:ClientSecret", - "value": "[parameters('authorClientSecret')]" - }, - { - "name": "AzureAd:ApplicationIdURI", - "value": "[if(variables('useFrontDoor'), concat('api://', variables('frontDoorDomain')), '')]" - }, - { - "name": "UserAppId", - "value": "[parameters('userClientId')]" - }, - { - "name": "UserAppPassword", - "value": "[parameters('userClientSecret')]" - }, - { - "name": "AuthorAppId", - "value": "[parameters('authorClientId')]" - }, - { - "name": "AuthorAppPassword", - "value": "[parameters('authorClientSecret')]" - }, - { - "name": "StorageAccountConnectionString", - "value": "[concat('DefaultEndpointsProtocol=https;AccountName=', variables('storageAccountName'), ';AccountKey=', listKeys(resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName')),'2015-05-01-preview').key1)]" - }, - { - "name": "ServiceBusConnection", - "value": "[listkeys(variables('authRuleResourceId'), '2017-04-01').primaryConnectionString]" - }, - { - "name": "AllowedTenants", - "value": "[parameters('tenantId')]" - }, - { - "name": "DisableTenantFilter", - "value": "false" - }, - { - "name": "AuthorizedCreatorUpns", - "value": "[parameters('senderUPNList')]" - }, - { - "name": "DisableAuthentication", - "value": "false" - }, - { - "name": "DisableCreatorUpnCheck", - "value": "false" - }, - { - "name": "APPINSIGHTS_INSTRUMENTATIONKEY", - "value": "[reference(resourceId('Microsoft.Insights/components/', variables('appInsightsName')), '2015-05-01').InstrumentationKey]" - }, - { - "name": "WEBSITE_NODE_DEFAULT_VERSION", - "value": "10.15.2" - } - ], - "cors": { - "supportCredentials": true, - "allowedOrigins": [ - "[concat('https://', variables('frontDoorDomain'))]" - ] - } - } - }, - "dependsOn": [ - "[resourceId('Microsoft.Web/serverfarms', variables('hostingPlanName'))]", - "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]", - "[resourceId('Microsoft.Insights/components', variables('appInsightsName'))]", - "[resourceId('Microsoft.ServiceBus/namespaces', variables('serviceBusNamespaceName'))]", - "[resourceId('Microsoft.Web/sites', variables('prepFunctionAppName'))]", - "[resourceId('Microsoft.Web/sites', variables('sendFunctionAppName'))]", - "[resourceId('Microsoft.Web/sites', variables('dataFunctionAppName'))]" - ], - "resources": [ - { - "apiVersion": "2016-08-01", - "name": "web", - "type": "sourcecontrols", - "condition": "[not(empty(parameters('gitRepoUrl')))]", - "dependsOn": [ - "[resourceId('Microsoft.Web/sites', variables('botAppName'))]" - ], - "properties": { - "RepoUrl": "[parameters('gitRepoUrl')]", - "branch": "[parameters('gitBranch')]", - "IsManualIntegration": true - } - } - ] - }, { "apiVersion": "2015-05-01", "name": "[variables('appInsightsName')]", @@ -486,101 +527,104 @@ ] }, { - "type": "Microsoft.ServiceBus/namespaces", - "apiVersion": "2017-04-01", - "name": "[variables('serviceBusNamespaceName')]", + "apiVersion": "2016-08-01", + "type": "Microsoft.Web/sites", + "name": "[variables('botAppName')]", "location": "[parameters('location')]", - "sku": { - "name": "Basic", - "tier": "Basic" + "kind": "app", + "identity": { + "type": "SystemAssigned" }, - "resources": [ - { - "type": "Queues", - "apiVersion": "2017-04-01", - "name": "[variables('serviceBusSendQueueName')]", - "dependsOn": [ - "[concat('Microsoft.ServiceBus/namespaces/', variables('serviceBusNamespaceName'))]" - ], - "properties": { - "lockDuration": "PT5M", - "maxSizeInMegabytes": 1024, - "requiresDuplicateDetection": false, - "requiresSession": false, - "defaultMessageTimeToLive": "P14D", - "deadLetteringOnMessageExpiration": false, - "enableBatchedOperations": true, - "duplicateDetectionHistoryTimeWindow": "PT10M", - "maxDeliveryCount": 10, - "status": "Active", - "enablePartitioning": false, - "enableExpress": false - } - }, - { - "type": "Queues", - "apiVersion": "2017-04-01", - "name": "[variables('serviceBusDataQueueName')]", - "dependsOn": [ - "[concat('Microsoft.ServiceBus/namespaces/', variables('serviceBusNamespaceName'))]" - ], - "properties": { - "lockDuration": "PT5M", - "maxSizeInMegabytes": 1024, - "requiresDuplicateDetection": false, - "requiresSession": false, - "defaultMessageTimeToLive": "P14D", - "deadLetteringOnMessageExpiration": false, - "enableBatchedOperations": true, - "duplicateDetectionHistoryTimeWindow": "PT10M", - "maxDeliveryCount": 10, - "status": "Active", - "enablePartitioning": false, - "enableExpress": false + "properties": { + "name": "[variables('botAppName')]", + "serverFarmId": "[resourceId('Microsoft.Web/serverfarms', variables('hostingPlanName'))]", + "enabled": true, + "reserved": false, + "clientAffinityEnabled": true, + "clientCertEnabled": false, + "hostNamesDisabled": false, + "containerSize": 0, + "dailyMemoryTimeQuota": 0, + "httpsOnly": true, + "siteConfig": { + "ftpsState": "Disabled", + "alwaysOn": "[not(variables('isSharedPlan'))]", + "cors": { + "supportCredentials": true, + "allowedOrigins": [ + "[concat('https://', variables('frontDoorDomain'))]" + ] } - }, + } + }, + "dependsOn": [ + "[resourceId('Microsoft.Web/serverfarms', variables('hostingPlanName'))]", + "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]", + "[resourceId('Microsoft.Insights/components', variables('appInsightsName'))]", + "[resourceId('Microsoft.ServiceBus/namespaces', variables('serviceBusNamespaceName'))]", + "[resourceId('Microsoft.Web/sites', variables('prepFunctionAppName'))]", + "[resourceId('Microsoft.Web/sites', variables('sendFunctionAppName'))]", + "[resourceId('Microsoft.Web/sites', variables('dataFunctionAppName'))]" + ], + "resources": [ { - "type": "Queues", - "apiVersion": "2017-04-01", - "name": "[variables('serviceBusPrepareToSendQueueName')]", + "apiVersion": "2015-08-01", + "name": "appsettings", + "type": "config", "dependsOn": [ - "[concat('Microsoft.ServiceBus/namespaces/', variables('serviceBusNamespaceName'))]" + "[resourceId('Microsoft.Web/sites', variables('botAppName'))]", + "[resourceId('Microsoft.KeyVault/vaults/', variables('keyVaultName'))]", + "[resourceId('Microsoft.KeyVault/vaults/secrets', variables('keyVaultName'), variables('StorageAccountSecretName'))]", + "[resourceId('Microsoft.KeyVault/vaults/secrets', variables('keyVaultName'), variables('ServiceBusSecretName'))]" ], "properties": { - "lockDuration": "PT5M", - "maxSizeInMegabytes": 1024, - "requiresDuplicateDetection": false, - "requiresSession": false, - "defaultMessageTimeToLive": "P14D", - "deadLetteringOnMessageExpiration": false, - "enableBatchedOperations": true, - "duplicateDetectionHistoryTimeWindow": "PT10M", - "maxDeliveryCount": 10, - "status": "Active", - "enablePartitioning": false, - "enableExpress": false + "PROJECT": "Source/CompanyCommunicator/Microsoft.Teams.Apps.CompanyCommunicator.csproj", + "SITE_ROLE": "app", + "i18n:DefaultCulture": "[variables('i18n:DefaultCulture')]", + "i18n:SupportedCultures": "[variables('i18n:SupportedCultures')]", + "ProactivelyInstallUserApp": "[variables('ProactivelyInstallUserApp')]", + "UserAppExternalId": "[variables('UserAppExternalId')]", + "AzureAd:TenantId": "[parameters('tenantId')]", + "AzureAd:ClientId": "[parameters('graphAppId')]", + "AzureAd:ClientSecret": "[concat('@Microsoft.KeyVault(SecretUri=', reference(variables('GraphAppSecretResourceId'),'2015-06-01').secretUriWithVersion, ')')]", + "AzureAd:ApplicationIdURI": "[if(variables('useFrontDoor'), concat('api://', variables('frontDoorDomain')), '')]", + "UserAppId": "[parameters('userClientId')]", + "UserAppPassword": "[concat('@Microsoft.KeyVault(SecretUri=', reference(variables('UserAppSecretResourceId'),'2015-06-01').secretUriWithVersion, ')')]", + "AuthorAppId": "[parameters('authorClientId')]", + "AuthorAppPassword": "[concat('@Microsoft.KeyVault(SecretUri=', reference(variables('AuthorAppSecretResourceId'),'2015-06-01').secretUriWithVersion, ')')]", + "GraphAppId": "[parameters('graphAppId')]", + "GraphAppPassword": "[concat('@Microsoft.KeyVault(SecretUri=', reference(variables('GraphAppSecretResourceId'),'2015-06-01').secretUriWithVersion, ')')]", + "StorageAccountConnectionString": "[concat('@Microsoft.KeyVault(SecretUri=', reference(variables('StorageAccountSecretResourceId'),'2015-06-01').secretUriWithVersion, ')')]", + "ServiceBusConnection": "[concat('@Microsoft.KeyVault(SecretUri=', reference(variables('ServiceBusSecretResourceId'),'2015-06-01').secretUriWithVersion, ')')]", + "ServiceBusNamespace": "[concat(variables('serviceBusNamespaceName'),'.servicebus.windows.net')]", + "StorageAccountName": "[variables('storageAccountName')]", + "UseManagedIdentity": "true", + "AllowedTenants": "[parameters('tenantId')]", + "DisableTenantFilter": "false", + "AuthorizedCreatorUpns": "[parameters('senderUPNList')]", + "UseCertificate": "false", + "DisableAuthentication": "false", + "DisableCreatorUpnCheck": "false", + "WEBSITE_LOAD_CERTIFICATES": "*", + "APPINSIGHTS_INSTRUMENTATIONKEY": "[concat('@Microsoft.KeyVault(SecretUri=', reference(variables('AppInsightsSecretResourceId'), '2015-06-01').secretUriWithVersion, ')')]", + "WEBSITE_NODE_DEFAULT_VERSION": "10.15.2", + "KeyVault:Url": "[variables('keyVaultUrl')]", + "DOTNET_ADD_GLOBAL_TOOLS_TO_PATH": "false" } }, { - "type": "Queues", - "apiVersion": "2017-04-01", - "name": "[variables('serviceBusExportQueueName')]", + "apiVersion": "2016-08-01", + "name": "web", + "type": "sourcecontrols", + "condition": "[not(empty(parameters('gitRepoUrl')))]", "dependsOn": [ - "[concat('Microsoft.ServiceBus/namespaces/', variables('serviceBusNamespaceName'))]" + "[resourceId('Microsoft.Web/sites', variables('botAppName'))]", + "[resourceId('Microsoft.Web/sites/config', variables('botAppName'), 'appsettings')]" ], "properties": { - "lockDuration": "PT5M", - "maxSizeInMegabytes": 1024, - "requiresDuplicateDetection": false, - "requiresSession": false, - "defaultMessageTimeToLive": "P14D", - "deadLetteringOnMessageExpiration": false, - "enableBatchedOperations": true, - "duplicateDetectionHistoryTimeWindow": "PT10M", - "maxDeliveryCount": 10, - "status": "Active", - "enablePartitioning": false, - "enableExpress": false + "RepoUrl": "[parameters('gitRepoUrl')]", + "branch": "[parameters('gitBranch')]", + "IsManualIntegration": true } } ] @@ -591,6 +635,9 @@ "name": "[variables('prepFunctionAppName')]", "location": "[parameters('location')]", "kind": "functionapp", + "identity": { + "type": "SystemAssigned" + }, "properties": { "name": "[variables('prepFunctionAppName')]", "serverFarmId": "[resourceId('Microsoft.Web/serverfarms', variables('hostingPlanName'))]", @@ -598,89 +645,8 @@ "clientAffinityEnabled": false, "httpsOnly": true, "siteConfig": { - "alwaysOn": "[not(variables('isSharedPlan'))]", - "appSettings": [ - { - "name": "PROJECT", - "value": "Source\\CompanyCommunicator.Prep.Func\\Microsoft.Teams.Apps.CompanyCommunicator.Prep.Func.csproj" - }, - { - "name": "SITE_ROLE", - "value": "function" - }, - { - "name": "i18n:DefaultCulture", - "value": "[variables('i18n:DefaultCulture')]" - }, - { - "name": "i18n:SupportedCultures", - "value": "[variables('i18n:SupportedCultures')]" - }, - { - "name": "ProactivelyInstallUserApp", - "value": "[variables('ProactivelyInstallUserApp')]" - }, - { - "name": "UserAppExternalId", - "value": "[variables('UserAppExternalId')]" - }, - { - "name": "AzureWebJobsStorage", - "value": "[concat('DefaultEndpointsProtocol=https;AccountName=',variables('storageAccountName'),';AccountKey=',listkeys(resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName')), '2015-05-01-preview').key1,';')]" - }, - { - "name": "AzureWebJobsDashboard", - "value": "[concat('DefaultEndpointsProtocol=https;AccountName=',variables('storageAccountName'),';AccountKey=',listkeys(resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName')), '2015-05-01-preview').key1,';')]" - }, - { - "name": "FUNCTIONS_EXTENSION_VERSION", - "value": "~3" - }, - { - "name": "FUNCTIONS_WORKER_RUNTIME", - "value": "dotnet" - }, - { - "name": "WEBSITE_CONTENTAZUREFILECONNECTIONSTRING", - "value": "[concat('DefaultEndpointsProtocol=https;AccountName=', variables('storageAccountName'), ';AccountKey=', listKeys(resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName')),'2015-05-01-preview').key1)]" - }, - { - "name": "WEBSITE_CONTENTSHARE", - "value": "[toLower(variables('prepFunctionAppName'))]" - }, - { - "name": "APPINSIGHTS_INSTRUMENTATIONKEY", - "value": "[reference(resourceId('microsoft.insights/components/', variables('appInsightsName')), '2015-05-01').InstrumentationKey]" - }, - { - "name": "AuthorAppId", - "value": "[parameters('authorClientId')]" - }, - { - "name": "AuthorAppPassword", - "value": "[parameters('authorClientSecret')]" - }, - { - "name": "UserAppId", - "value": "[parameters('userClientId')]" - }, - { - "name": "UserAppPassword", - "value": "[parameters('userClientSecret')]" - }, - { - "name": "TenantId", - "value": "[parameters('tenantId')]" - }, - { - "name": "StorageAccountConnectionString", - "value": "[concat('DefaultEndpointsProtocol=https;AccountName=', variables('storageAccountName'), ';AccountKey=', listKeys(resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName')),'2015-05-01-preview').key1)]" - }, - { - "name": "ServiceBusConnection", - "value": "[listkeys(variables('authRuleResourceId'), '2017-04-01').primaryConnectionString]" - } - ] + "ftpsState": "Disabled", + "alwaysOn": "[not(variables('isSharedPlan'))]" } }, "dependsOn": [ @@ -689,13 +655,59 @@ "[resourceId('Microsoft.ServiceBus/namespaces', variables('serviceBusNamespaceName'))]" ], "resources": [ + { + "apiVersion": "2015-08-01", + "name": "appsettings", + "type": "config", + "dependsOn": [ + "[resourceId('Microsoft.Web/sites', variables('prepFunctionAppName'))]", + "[resourceId('Microsoft.KeyVault/vaults/', variables('keyVaultName'))]", + "[resourceId('Microsoft.KeyVault/vaults/secrets', variables('keyVaultName'), variables('StorageAccountSecretName'))]", + "[resourceId('Microsoft.KeyVault/vaults/secrets', variables('keyVaultName'), variables('ServiceBusSecretName'))]" + ], + "properties": { + "PROJECT": "Source\\CompanyCommunicator.Prep.Func\\Microsoft.Teams.Apps.CompanyCommunicator.Prep.Func.csproj", + "SITE_ROLE": "function", + "i18n:DefaultCulture": "[variables('i18n:DefaultCulture')]", + "i18n:SupportedCultures": "[variables('i18n:SupportedCultures')]", + "ProactivelyInstallUserApp": "[variables('ProactivelyInstallUserApp')]", + "UserAppExternalId": "[variables('UserAppExternalId')]", + "TenantId": "[parameters('tenantId')]", + "UserAppId": "[parameters('userClientId')]", + "UserAppPassword": "[concat('@Microsoft.KeyVault(SecretUri=', reference(variables('UserAppSecretResourceId'),'2015-06-01').secretUriWithVersion, ')')]", + "AuthorAppId": "[parameters('authorClientId')]", + "AuthorAppPassword": "[concat('@Microsoft.KeyVault(SecretUri=', reference(variables('AuthorAppSecretResourceId'),'2015-06-01').secretUriWithVersion, ')')]", + "GraphAppId": "[parameters('graphAppId')]", + "GraphAppPassword": "[concat('@Microsoft.KeyVault(SecretUri=', reference(variables('GraphAppSecretResourceId'),'2015-06-01').secretUriWithVersion, ')')]", + "StorageAccountConnectionString": "[concat('@Microsoft.KeyVault(SecretUri=', reference(variables('StorageAccountSecretResourceId'),'2015-06-01').secretUriWithVersion, ')')]", + "ServiceBusConnection": "[concat('@Microsoft.KeyVault(SecretUri=', reference(variables('ServiceBusSecretResourceId'),'2015-06-01').secretUriWithVersion, ')')]", + "ServiceBusNamespace": "[concat(variables('serviceBusNamespaceName'),'.servicebus.windows.net')]", + "StorageAccountName": "[variables('storageAccountName')]", + "UseManagedIdentity": "true", + "UseCertificate": "false", + "WEBSITE_LOAD_CERTIFICATES": "*", + "APPINSIGHTS_INSTRUMENTATIONKEY": "[concat('@Microsoft.KeyVault(SecretUri=', reference(variables('AppInsightsSecretResourceId'), '2015-06-01').secretUriWithVersion, ')')]", + "KeyVault:Url": "[variables('keyVaultUrl')]", + "AzureWebJobsStorage": "[concat('DefaultEndpointsProtocol=https;AccountName=', variables('storageAccountName'), ';AccountKey=', listKeys(resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName')),'2015-05-01-preview').key1)]", + "AzureWebJobsDashboard": "[concat('@Microsoft.KeyVault(SecretUri=', reference(variables('StorageAccountSecretResourceId'),'2015-06-01').secretUriWithVersion, ')')]", + "FUNCTIONS_EXTENSION_VERSION": "~3", + "FUNCTIONS_WORKER_RUNTIME": "dotnet", + "WEBSITE_CONTENTAZUREFILECONNECTIONSTRING": "[concat('DefaultEndpointsProtocol=https;AccountName=', variables('storageAccountName'), ';AccountKey=', listKeys(resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName')),'2015-05-01-preview').key1)]", + "WEBSITE_CONTENTSHARE": "[toLower(variables('prepFunctionAppName'))]", + "AzureFunctionsJobHost__extensions__durableTask__maxConcurrentOrchestratorFunctions": "3", + "AzureFunctionsJobHost__extensions__durableTask__maxConcurrentActivityFunctions": "10", + "DOTNET_ADD_GLOBAL_TOOLS_TO_PATH": "false", + "WEBSITE_NODE_DEFAULT_VERSION": "10.15.2" + } + }, { "apiVersion": "2015-08-01", "name": "web", "type": "sourcecontrols", "condition": "[not(empty(parameters('gitRepoUrl')))]", "dependsOn": [ - "[resourceId('Microsoft.Web/sites', variables('prepFunctionAppName'))]" + "[resourceId('Microsoft.Web/sites', variables('prepFunctionAppName'))]", + "[resourceId('Microsoft.Web/sites/config', variables('prepFunctionAppName'), 'appsettings')]" ], "properties": { "RepoUrl": "[parameters('gitRepoUrl')]", @@ -711,6 +723,9 @@ "name": "[variables('sendFunctionAppName')]", "location": "[parameters('location')]", "kind": "functionapp", + "identity": { + "type": "SystemAssigned" + }, "properties": { "name": "[variables('sendFunctionAppName')]", "serverFarmId": "[resourceId('Microsoft.Web/serverfarms', variables('hostingPlanName'))]", @@ -718,73 +733,8 @@ "clientAffinityEnabled": false, "httpsOnly": true, "siteConfig": { - "alwaysOn": "[not(variables('isSharedPlan'))]", - "appSettings": [ - { - "name": "PROJECT", - "value": "Source\\CompanyCommunicator.Send.Func\\Microsoft.Teams.Apps.CompanyCommunicator.Send.Func.csproj" - }, - { - "name": "SITE_ROLE", - "value": "function" - }, - { - "name": "i18n:DefaultCulture", - "value": "[variables('i18n:DefaultCulture')]" - }, - { - "name": "i18n:SupportedCultures", - "value": "[variables('i18n:SupportedCultures')]" - }, - { - "name": "AzureWebJobsStorage", - "value": "[concat('DefaultEndpointsProtocol=https;AccountName=',variables('storageAccountName'),';AccountKey=',listkeys(resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName')), '2015-05-01-preview').key1,';')]" - }, - { - "name": "AzureWebJobsDashboard", - "value": "[concat('DefaultEndpointsProtocol=https;AccountName=',variables('storageAccountName'),';AccountKey=',listkeys(resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName')), '2015-05-01-preview').key1,';')]" - }, - { - "name": "FUNCTIONS_EXTENSION_VERSION", - "value": "~3" - }, - { - "name": "FUNCTIONS_WORKER_RUNTIME", - "value": "dotnet" - }, - { - "name": "WEBSITE_CONTENTAZUREFILECONNECTIONSTRING", - "value": "[concat('DefaultEndpointsProtocol=https;AccountName=', variables('storageAccountName'), ';AccountKey=', listKeys(resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName')),'2015-05-01-preview').key1)]" - }, - { - "name": "WEBSITE_CONTENTSHARE", - "value": "[toLower(variables('sendFunctionAppName'))]" - }, - { - "name": "APPINSIGHTS_INSTRUMENTATIONKEY", - "value": "[reference(resourceId('microsoft.insights/components/', variables('appInsightsName')), '2015-05-01').InstrumentationKey]" - }, - { - "name": "MaxNumberOfAttempts", - "value": "5" - }, - { - "name": "UserAppId", - "value": "[parameters('userClientId')]" - }, - { - "name": "UserAppPassword", - "value": "[parameters('userClientSecret')]" - }, - { - "name": "StorageAccountConnectionString", - "value": "[concat('DefaultEndpointsProtocol=https;AccountName=', variables('storageAccountName'), ';AccountKey=', listKeys(resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName')),'2015-05-01-preview').key1)]" - }, - { - "name": "ServiceBusConnection", - "value": "[listkeys(variables('authRuleResourceId'), '2017-04-01').primaryConnectionString]" - } - ] + "ftpsState": "Disabled", + "alwaysOn": "[not(variables('isSharedPlan'))]" } }, "dependsOn": [ @@ -793,13 +743,52 @@ "[resourceId('Microsoft.ServiceBus/namespaces', variables('serviceBusNamespaceName'))]" ], "resources": [ + { + "apiVersion": "2015-08-01", + "name": "appsettings", + "type": "config", + "dependsOn": [ + "[resourceId('Microsoft.Web/sites', variables('sendFunctionAppName'))]", + "[resourceId('Microsoft.KeyVault/vaults/', variables('keyVaultName'))]", + "[resourceId('Microsoft.KeyVault/vaults/secrets', variables('keyVaultName'), variables('StorageAccountSecretName'))]", + "[resourceId('Microsoft.KeyVault/vaults/secrets', variables('keyVaultName'), variables('ServiceBusSecretName'))]" + ], + "properties": { + "PROJECT": "Source\\CompanyCommunicator.Send.Func\\Microsoft.Teams.Apps.CompanyCommunicator.Send.Func.csproj", + "SITE_ROLE": "function", + "i18n:DefaultCulture": "[variables('i18n:DefaultCulture')]", + "i18n:SupportedCultures": "[variables('i18n:SupportedCultures')]", + "ProactivelyInstallUserApp": "[variables('ProactivelyInstallUserApp')]", + "UserAppId": "[parameters('userClientId')]", + "UserAppPassword": "[concat('@Microsoft.KeyVault(SecretUri=', reference(variables('UserAppSecretResourceId'),'2015-06-01').secretUriWithVersion, ')')]", + "StorageAccountConnectionString": "[concat('@Microsoft.KeyVault(SecretUri=', reference(variables('StorageAccountSecretResourceId'),'2015-06-01').secretUriWithVersion, ')')]", + "ServiceBusConnection": "[concat('@Microsoft.KeyVault(SecretUri=', reference(variables('ServiceBusSecretResourceId'),'2015-06-01').secretUriWithVersion, ')')]", + "ServiceBusNamespace": "[concat(variables('serviceBusNamespaceName'),'.servicebus.windows.net')]", + "StorageAccountName": "[variables('storageAccountName')]", + "UseManagedIdentity": "true", + "UseCertificate": "false", + "MaxNumberOfAttempts": "5", + "WEBSITE_LOAD_CERTIFICATES": "*", + "APPINSIGHTS_INSTRUMENTATIONKEY": "[concat('@Microsoft.KeyVault(SecretUri=', reference(variables('AppInsightsSecretResourceId'), '2015-06-01').secretUriWithVersion, ')')]", + "KeyVault:Url": "[variables('keyVaultUrl')]", + "AzureWebJobsStorage": "[concat('DefaultEndpointsProtocol=https;AccountName=', variables('storageAccountName'), ';AccountKey=', listKeys(resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName')),'2015-05-01-preview').key1)]", + "AzureWebJobsDashboard": "[concat('@Microsoft.KeyVault(SecretUri=', reference(variables('StorageAccountSecretResourceId'),'2015-06-01').secretUriWithVersion, ')')]", + "FUNCTIONS_EXTENSION_VERSION": "~3", + "FUNCTIONS_WORKER_RUNTIME": "dotnet", + "WEBSITE_CONTENTAZUREFILECONNECTIONSTRING": "[concat('DefaultEndpointsProtocol=https;AccountName=', variables('storageAccountName'), ';AccountKey=', listKeys(resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName')),'2015-05-01-preview').key1)]", + "WEBSITE_CONTENTSHARE": "[toLower(variables('sendFunctionAppName'))]", + "DOTNET_ADD_GLOBAL_TOOLS_TO_PATH": "false", + "WEBSITE_NODE_DEFAULT_VERSION": "10.15.2" + } + }, { "apiVersion": "2015-08-01", "name": "web", "type": "sourcecontrols", "condition": "[not(empty(parameters('gitRepoUrl')))]", "dependsOn": [ - "[resourceId('Microsoft.Web/sites', variables('sendFunctionAppName'))]" + "[resourceId('Microsoft.Web/sites', variables('sendFunctionAppName'))]", + "[resourceId('Microsoft.Web/sites/config', variables('sendFunctionAppName'), 'appsettings')]" ], "properties": { "RepoUrl": "[parameters('gitRepoUrl')]", @@ -815,6 +804,9 @@ "name": "[variables('dataFunctionAppName')]", "location": "[parameters('location')]", "kind": "functionapp", + "identity": { + "type": "SystemAssigned" + }, "properties": { "name": "[variables('dataFunctionAppName')]", "serverFarmId": "[resourceId('Microsoft.Web/serverfarms', variables('hostingPlanName'))]", @@ -822,85 +814,8 @@ "clientAffinityEnabled": false, "httpsOnly": true, "siteConfig": { - "alwaysOn": "[not(variables('isSharedPlan'))]", - "appSettings": [ - { - "name": "PROJECT", - "value": "Source\\CompanyCommunicator.Data.Func\\Microsoft.Teams.Apps.CompanyCommunicator.Data.Func.csproj" - }, - { - "name": "SITE_ROLE", - "value": "function" - }, - { - "name": "i18n:DefaultCulture", - "value": "[variables('i18n:DefaultCulture')]" - }, - { - "name": "i18n:SupportedCultures", - "value": "[variables('i18n:SupportedCultures')]" - }, - { - "name": "AzureWebJobsStorage", - "value": "[concat('DefaultEndpointsProtocol=https;AccountName=',variables('storageAccountName'),';AccountKey=',listkeys(resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName')), '2015-05-01-preview').key1,';')]" - }, - { - "name": "AzureWebJobsDashboard", - "value": "[concat('DefaultEndpointsProtocol=https;AccountName=',variables('storageAccountName'),';AccountKey=',listkeys(resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName')), '2015-05-01-preview').key1,';')]" - }, - { - "name": "FUNCTIONS_EXTENSION_VERSION", - "value": "~3" - }, - { - "name": "FUNCTIONS_WORKER_RUNTIME", - "value": "dotnet" - }, - { - "name": "WEBSITE_CONTENTAZUREFILECONNECTIONSTRING", - "value": "[concat('DefaultEndpointsProtocol=https;AccountName=', variables('storageAccountName'), ';AccountKey=', listKeys(resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName')),'2015-05-01-preview').key1)]" - }, - { - "name": "WEBSITE_CONTENTSHARE", - "value": "[toLower(variables('dataFunctionAppName'))]" - }, - { - "name": "APPINSIGHTS_INSTRUMENTATIONKEY", - "value": "[reference(resourceId('microsoft.insights/components/', variables('appInsightsName')), '2015-05-01').InstrumentationKey]" - }, - { - "name": "AuthorAppId", - "value": "[parameters('authorClientId')]" - }, - { - "name": "AuthorAppPassword", - "value": "[parameters('authorClientSecret')]" - }, - { - "name": "UserAppId", - "value": "[parameters('userClientId')]" - }, - { - "name": "UserAppPassword", - "value": "[parameters('userClientSecret')]" - }, - { - "name": "CleanUpScheduleTriggerTime", - "value": "30 23 * * *" - }, - { - "name": "CleanUpFile", - "value": "1" - }, - { - "name": "StorageAccountConnectionString", - "value": "[concat('DefaultEndpointsProtocol=https;AccountName=', variables('storageAccountName'), ';AccountKey=', listKeys(resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName')),'2015-05-01-preview').key1)]" - }, - { - "name": "ServiceBusConnection", - "value": "[listkeys(variables('authRuleResourceId'), '2017-04-01').primaryConnectionString]" - } - ] + "ftpsState": "Disabled", + "alwaysOn": "[not(variables('isSharedPlan'))]" } }, "dependsOn": [ @@ -909,13 +824,55 @@ "[resourceId('Microsoft.ServiceBus/namespaces', variables('serviceBusNamespaceName'))]" ], "resources": [ + { + "apiVersion": "2015-08-01", + "name": "appsettings", + "type": "config", + "dependsOn": [ + "[resourceId('Microsoft.Web/sites', variables('dataFunctionAppName'))]", + "[resourceId('Microsoft.KeyVault/vaults/', variables('keyVaultName'))]", + "[resourceId('Microsoft.KeyVault/vaults/secrets', variables('keyVaultName'), variables('StorageAccountSecretName'))]", + "[resourceId('Microsoft.KeyVault/vaults/secrets', variables('keyVaultName'), variables('ServiceBusSecretName'))]" + ], + "properties": { + "PROJECT": "Source\\CompanyCommunicator.Data.Func\\Microsoft.Teams.Apps.CompanyCommunicator.Data.Func.csproj", + "SITE_ROLE": "function", + "i18n:DefaultCulture": "[variables('i18n:DefaultCulture')]", + "i18n:SupportedCultures": "[variables('i18n:SupportedCultures')]", + "ProactivelyInstallUserApp": "[variables('ProactivelyInstallUserApp')]", + "UserAppId": "[parameters('userClientId')]", + "UserAppPassword": "[concat('@Microsoft.KeyVault(SecretUri=', reference(variables('UserAppSecretResourceId'),'2015-06-01').secretUriWithVersion, ')')]", + "AuthorAppId": "[parameters('authorClientId')]", + "AuthorAppPassword": "[concat('@Microsoft.KeyVault(SecretUri=', reference(variables('AuthorAppSecretResourceId'),'2015-06-01').secretUriWithVersion, ')')]", + "StorageAccountConnectionString": "[concat('@Microsoft.KeyVault(SecretUri=', reference(variables('StorageAccountSecretResourceId'),'2015-06-01').secretUriWithVersion, ')')]", + "ServiceBusConnection": "[concat('@Microsoft.KeyVault(SecretUri=', reference(variables('ServiceBusSecretResourceId'),'2015-06-01').secretUriWithVersion, ')')]", + "ServiceBusNamespace": "[concat(variables('serviceBusNamespaceName'),'.servicebus.windows.net')]", + "StorageAccountName": "[variables('storageAccountName')]", + "UseManagedIdentity": "true", + "UseCertificate": "false", + "WEBSITE_LOAD_CERTIFICATES": "*", + "APPINSIGHTS_INSTRUMENTATIONKEY": "[concat('@Microsoft.KeyVault(SecretUri=', reference(variables('AppInsightsSecretResourceId'), '2015-06-01').secretUriWithVersion, ')')]", + "KeyVault:Url": "[variables('keyVaultUrl')]", + "AzureWebJobsStorage": "[concat('DefaultEndpointsProtocol=https;AccountName=', variables('storageAccountName'), ';AccountKey=', listKeys(resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName')),'2015-05-01-preview').key1)]", + "AzureWebJobsDashboard": "[concat('@Microsoft.KeyVault(SecretUri=', reference(variables('StorageAccountSecretResourceId'),'2015-06-01').secretUriWithVersion, ')')]", + "FUNCTIONS_EXTENSION_VERSION": "~3", + "FUNCTIONS_WORKER_RUNTIME": "dotnet", + "WEBSITE_CONTENTAZUREFILECONNECTIONSTRING": "[concat('DefaultEndpointsProtocol=https;AccountName=', variables('storageAccountName'), ';AccountKey=', listKeys(resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName')),'2015-05-01-preview').key1)]", + "WEBSITE_CONTENTSHARE": "[toLower(variables('dataFunctionAppName'))]", + "CleanUpScheduleTriggerTime": "30 23 * * *", + "CleanUpFile": "1", + "DOTNET_ADD_GLOBAL_TOOLS_TO_PATH": "false", + "WEBSITE_NODE_DEFAULT_VERSION": "10.15.2" + } + }, { "apiVersion": "2015-08-01", "name": "web", "type": "sourcecontrols", "condition": "[not(empty(parameters('gitRepoUrl')))]", "dependsOn": [ - "[resourceId('Microsoft.Web/sites', variables('dataFunctionAppName'))]" + "[resourceId('Microsoft.Web/sites', variables('dataFunctionAppName'))]", + "[resourceId('Microsoft.Web/sites/config', variables('dataFunctionAppName'), 'appsettings')]" ], "properties": { "RepoUrl": "[parameters('gitRepoUrl')]", @@ -925,6 +882,296 @@ } ] }, + { + "type": "Microsoft.KeyVault/vaults", + "name": "[variables('keyvaultName')]", + "apiVersion": "2016-10-01", + "location": "[parameters('location')]", + + "tags": { + "displayName": "KeyVault" + }, + "properties": { + "tenantId": "[variables('subscriptionTenantId')]", + "enabledForDeployment": false, + "enabledForDiskEncryption": false, + "enabledForTemplateDeployment": true, + "accessPolicies": [ + { + "tenantId": "[reference(concat('Microsoft.Web/sites/', variables('botAppName')), '2018-02-01', 'Full').identity.tenantId]", + "objectId": "[reference(concat('Microsoft.Web/sites/', variables('botAppName')), '2018-02-01', 'Full').identity.principalId]", + "permissions": { + "keys": [], + "secrets": [ + "Get", + "Set", + "Restore" + ], + "certificates": [] + }, + "dependsOn": [ + "[resourceId('Microsoft.Web/sites', variables('botAppName'))]" + ] + }, + { + "tenantId": "[reference(concat('Microsoft.Web/sites/', variables('prepFunctionAppName')), '2018-02-01', 'Full').identity.tenantId]", + "objectId": "[reference(concat('Microsoft.Web/sites/', variables('prepFunctionAppName')), '2018-02-01', 'Full').identity.principalId]", + "permissions": { + "keys": [], + "secrets": [ + "Get" + ], + "certificates": [ + "Get" + ] + }, + "dependsOn": [ + "[resourceId('Microsoft.Web/sites', variables('prepFunctionAppName'))]" + ] + }, + { + "tenantId": "[reference(concat('Microsoft.Web/sites/', variables('sendFunctionAppName')), '2018-02-01', 'Full').identity.tenantId]", + "objectId": "[reference(concat('Microsoft.Web/sites/', variables('sendFunctionAppName')), '2018-02-01', 'Full').identity.principalId]", + "permissions": { + "keys": [], + "secrets": [ + "Get" + ], + "certificates": [ + "Get" + ] + }, + "dependsOn": [ + "[resourceId('Microsoft.Web/sites', variables('sendFunctionAppName'))]" + ] + }, + { + "tenantId": "[reference(concat('Microsoft.Web/sites/', variables('dataFunctionAppName')), '2018-02-01', 'Full').identity.tenantId]", + "objectId": "[reference(concat('Microsoft.Web/sites/', variables('dataFunctionAppName')), '2018-02-01', 'Full').identity.principalId]", + "permissions": { + "keys": [], + "secrets": [ + "Get" + ], + "certificates": [ + "Get" + ] + }, + "dependsOn": [ + "[resourceId('Microsoft.Web/sites', variables('dataFunctionAppName'))]" + ] + } + ], + "sku": { + "name": "Standard", + "family": "A" + }, + "networkAcls": { + "bypass": "AzureServices", + "defaultAction": "Allow" + } + }, + "resources": [ + { + "type": "secrets", + "apiVersion": "2016-10-01", + "name": "[variables('StorageAccountSecretName')]", + "location": "[parameters('location')]", + "dependsOn": [ + "[resourceId('Microsoft.KeyVault/vaults', variables('keyVaultName'))]", + "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]" + ], + "properties": { + "value": "[concat('DefaultEndpointsProtocol=https;AccountName=', variables('storageAccountName'), ';AccountKey=', listKeys(resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName')),'2015-05-01-preview').key1)]", + "attributes": { + "enabled": true + } + } + }, + { + "type": "secrets", + "apiVersion": "2016-10-01", + "name": "[variables('ServiceBusSecretName')]", + "location": "[parameters('location')]", + "dependsOn": [ + "[resourceId('Microsoft.KeyVault/vaults', variables('keyVaultName'))]", + "[resourceId('Microsoft.ServiceBus/namespaces', variables('serviceBusNamespaceName'))]" + ], + "properties": { + "value": "[listkeys(variables('authRuleResourceId'), '2017-04-01').primaryConnectionString]", + "attributes": { + "enabled": true + } + } + }, + { + "type": "secrets", + "apiVersion": "2016-10-01", + "name": "[variables('UserAppSecretName')]", + "location": "[parameters('location')]", + "dependsOn": [ + "[resourceId('Microsoft.KeyVault/vaults', variables('keyvaultName'))]" + ], + "properties": { + "value": "[parameters('userClientSecret')]", + "attributes": { + "enabled": true + } + } + }, + { + "type": "secrets", + "apiVersion": "2016-10-01", + "name": "[variables('AuthorAppSecretName')]", + "location": "[parameters('location')]", + "dependsOn": [ + "[resourceId('Microsoft.KeyVault/vaults', variables('keyvaultName'))]" + ], + "properties": { + "value": "[parameters('authorClientSecret')]", + "attributes": { + "enabled": true + } + } + }, + { + "type": "secrets", + "apiVersion": "2016-10-01", + "name": "[variables('GraphAppSecretName')]", + "location": "[parameters('location')]", + "dependsOn": [ + "[resourceId('Microsoft.KeyVault/vaults', variables('keyvaultName'))]" + ], + "properties": { + "value": "[parameters('graphAppSecret')]", + "attributes": { + "enabled": true + } + } + }, + { + "type": "secrets", + "name": "[variables('AppInsightsSecretName')]", + "location": "[parameters('location')]", + "apiVersion": "2018-02-14", + "dependsOn": [ + "[resourceId('Microsoft.KeyVault/vaults/', variables('keyVaultName'))]", + "[resourceId('Microsoft.Insights/components', variables('appInsightsName'))]" + ], + "properties": { + "value": "[reference(resourceId('Microsoft.Insights/components/', variables('appInsightsName')), '2015-05-01').InstrumentationKey]", + "attributes": { + "enabled": true + } + } + } + ] + }, + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2020-04-01-preview", + "name": "[parameters('ServiceBusWebAppRoleNameGuid')]", + "scope": "[concat('Microsoft.ServiceBus/namespaces', '/', variables('serviceBusNamespaceName'))]", + "dependsOn": [ + "[resourceId('Microsoft.ServiceBus/namespaces', variables('serviceBusNamespaceName'))]", + "[resourceId('Microsoft.Web/sites', variables('botAppName'))]" + ], + "properties": { + "roleDefinitionId": "[variables('AzureserviceBusDataOwner')]", + "principalId": "[reference(resourceId('Microsoft.Web/sites', variables('botAppName')), '2019-08-01', 'Full').identity.principalId]", + "principalType": "ServicePrincipal" + } + }, + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2020-04-01-preview", + "name": "[parameters('ServiceBusPrepFuncRoleNameGuid')]", + "scope": "[concat('Microsoft.ServiceBus/namespaces', '/', variables('serviceBusNamespaceName'))]", + "dependsOn": [ + "[resourceId('Microsoft.ServiceBus/namespaces', variables('serviceBusNamespaceName'))]", + "[resourceId('Microsoft.Web/sites', variables('prepFunctionAppName'))]" + ], + "properties": { + "roleDefinitionId": "[variables('AzureserviceBusDataOwner')]", + "principalId": "[reference(resourceId('Microsoft.Web/sites', variables('prepFunctionAppName')), '2019-08-01', 'Full').identity.principalId]", + "principalType": "ServicePrincipal" + } + }, + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2020-04-01-preview", + "name": "[parameters('ServiceBusSendFuncRoleNameGuid')]", + "scope": "[concat('Microsoft.ServiceBus/namespaces', '/', variables('serviceBusNamespaceName'))]", + "dependsOn": [ + "[resourceId('Microsoft.ServiceBus/namespaces', variables('serviceBusNamespaceName'))]", + "[resourceId('Microsoft.Web/sites', variables('sendFunctionAppName'))]" + ], + "properties": { + "roleDefinitionId": "[variables('AzureserviceBusDataOwner')]", + "principalId": "[reference(resourceId('Microsoft.Web/sites', variables('sendFunctionAppName')), '2019-08-01', 'Full').identity.principalId]", + "principalType": "ServicePrincipal" + } + }, + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2020-04-01-preview", + "name": "[parameters('ServiceBusDataFuncRoleNameGuid')]", + "scope": "[concat('Microsoft.ServiceBus/namespaces', '/', variables('serviceBusNamespaceName'))]", + "dependsOn": [ + "[resourceId('Microsoft.ServiceBus/namespaces', variables('serviceBusNamespaceName'))]", + "[resourceId('Microsoft.Web/sites', variables('dataFunctionAppName'))]" + ], + "properties": { + "roleDefinitionId": "[variables('AzureserviceBusDataOwner')]", + "principalId": "[reference(resourceId('Microsoft.Web/sites', variables('dataFunctionAppName')), '2019-08-01', 'Full').identity.principalId]", + "principalType": "ServicePrincipal" + } + }, + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2020-04-01-preview", + "name": "[parameters('StorageAccountWebAppRoleNameGuid')]", + "scope": "[concat('Microsoft.Storage/storageAccounts', '/', variables('storageAccountName'))]", + "dependsOn": [ + "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]", + "[resourceId('Microsoft.Web/sites', variables('botAppName'))]" + ], + "properties": { + "roleDefinitionId": "[variables('StorageBlobDataContributor')]", + "principalId": "[reference(resourceId('Microsoft.Web/sites', variables('botAppName')), '2019-08-01', 'Full').identity.principalId]", + "principalType": "ServicePrincipal" + } + }, + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2020-04-01-preview", + "name": "[parameters('StorageAccountPrepFuncRoleNameGuid')]", + "scope": "[concat('Microsoft.Storage/storageAccounts', '/', variables('storageAccountName'))]", + "dependsOn": [ + "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]", + "[resourceId('Microsoft.Web/sites', variables('prepFunctionAppName'))]" + ], + "properties": { + "roleDefinitionId": "[variables('StorageBlobDataContributor')]", + "principalId": "[reference(resourceId('Microsoft.Web/sites', variables('prepFunctionAppName')), '2019-08-01', 'Full').identity.principalId]", + "principalType": "ServicePrincipal" + } + }, + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2020-04-01-preview", + "name": "[parameters('StorageAccountDataFuncRoleNameGuid')]", + "scope": "[concat('Microsoft.Storage/storageAccounts', '/', variables('storageAccountName'))]", + "dependsOn": [ + "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]", + "[resourceId('Microsoft.Web/sites', variables('dataFunctionAppName'))]" + ], + "properties": { + "roleDefinitionId": "[variables('StorageBlobDataContributor')]", + "principalId": "[reference(resourceId('Microsoft.Web/sites', variables('dataFunctionAppName')), '2019-08-01', 'Full').identity.principalId]", + "principalType": "ServicePrincipal" + } + }, { "apiVersion": "2019-04-01", "type": "Microsoft.Network/frontDoors", @@ -1049,6 +1296,10 @@ } ], "outputs": { + "keyVaultName": { + "type": "string", + "value": "[variables('keyvaultName')]" + }, "authorBotId": { "type": "string", "value": "[parameters('authorClientId')]" diff --git a/Deployment/azuredeploywithcert.json b/Deployment/azuredeploywithcert.json new file mode 100644 index 000000000..ce378839d --- /dev/null +++ b/Deployment/azuredeploywithcert.json @@ -0,0 +1,1276 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "baseResourceName": { + "type": "string", + "minLength": 1, + "metadata": { + "description": "The base name to use for the resources that will be provisioned." + } + }, + "userClientId": { + "type": "string", + "minLength": 36, + "maxLength": 36, + "metadata": { + "description": "The client ID of the user bot Azure AD app, e.g., 123e4567-e89b-12d3-a456-426655440000." + } + }, + "userAppCertName": { + "type": "string", + "minLength": 1, + "metadata": { + "description": "The X.509 certificate name of the user bot Azure AD app." + } + }, + "authorClientId": { + "type": "string", + "minLength": 36, + "maxLength": 36, + "metadata": { + "description": "The client ID of the author bot Azure AD app, e.g., 123e4567-e89b-12d3-a456-426655440000." + } + }, + "authorAppCertName": { + "type": "string", + "minLength": 1, + "metadata": { + "description": "The X.509 certificate name of the author bot Azure AD app." + } + }, + "graphAppId": { + "type": "string", + "minLength": 36, + "maxLength": 36, + "metadata": { + "description": "The client ID of the Microsoft Graph Azure AD app, e.g., 123e4567-e89b-12d3-a456-426655440000." + } + }, + "graphAppCertName": { + "type": "string", + "minLength": 1, + "metadata": { + "description": "The X.509 certificate name of the Microsoft Graph Azure AD app." + } + }, + "senderUPNList": { + "type": "string", + "minLength": 1, + "metadata": { + "description": "Semicolon-delimited list of the user principal names (UPNs) allowed to send messages." + } + }, + "ProactivelyInstallUserApp": { + "defaultValue": true, + "type": "Bool", + "metadata": { + "description": "If proactive app installation should be enabled." + } + }, + "objectId": { + "type": "string", + "metadata": { + "description": "Object Id of the user to deploy to (If you are not sure how to get Object ID, please check Azure Active Directory in Azure Portal. Under Manage, click Users and select the appropriate user. The Object ID is shown in the Identity section). e.g 98f3ece2-3a5a-428b-aa4f-4c41b3f6eef0." + } + }, + "UserAppExternalId": { + "defaultValue": "148a66bb-e83d-425a-927d-09f4299a9274", + "minLength": 1, + "type": "String", + "metadata": { + "description": "User app external ID." + } + }, + "DefaultCulture": { + "defaultValue": "en-US", + "allowedValues": [ + "ar-SA", + "de-DE", + "en-US", + "es-ES", + "fr-FR", + "he-IL", + "ja-JP", + "ko-KR", + "pt-BR", + "ru-RU", + "zh-CN", + "zh-TW" + ], + "minLength": 1, + "type": "String", + "metadata": { + "description": "Default culture." + } + }, + "SupportedCultures": { + "defaultValue": "ar-SA,de-DE,en-US,es-ES,fr-FR,he-IL,ja-JP,ko-KR,pt-BR,ru-RU,zh-CN,zh-TW", + "minLength": 1, + "type": "String", + "metadata": { + "description": "Comma-delimited list of the supported cultures." + } + }, + "customDomainOption": { + "type": "string", + "allowedValues": [ + "Custom domain name (recommended)", + "Azure Front Door" + ], + "defaultValue": "Azure Front Door", + "metadata": { + "description": "How the app will be hosted on a domain that is not *.azurewebsites.net. Azure Front Door is an easy option that the template can set up automatically, but it comes with ongoing monthly costs. " + } + }, + "appDisplayName": { + "type": "string", + "defaultValue": "Company Communicator", + "minLength": 1, + "metadata": { + "description": "The app (and bot) display name." + } + }, + "appDescription": { + "type": "string", + "defaultValue": "Broadcast messages to multiple teams and people in one go", + "minLength": 1, + "metadata": { + "description": "The app (and bot) description." + } + }, + "appIconUrl": { + "type": "string", + "minLength": 1, + "defaultValue": "https://raw.githubusercontent.com/OfficeDev/microsoft-teams-company-communicator-app/master/Manifest/color.png", + "metadata": { + "description": "The link to the icon for the app. It must resolve to a PNG file." + } + }, + "tenantId": { + "type": "string", + "defaultValue": "[subscription().tenantId]", + "minLength": 1, + "maxLength": 36, + "metadata": { + "description": "The ID of the tenant to which the app will be deployed." + } + }, + "hostingPlanSku": { + "type": "string", + "allowedValues": [ + "Basic", + "Standard", + "Premium" + ], + "defaultValue": "Standard", + "metadata": { + "description": "The pricing tier for the hosting plan." + } + }, + "hostingPlanSize": { + "type": "string", + "allowedValues": [ + "1", + "2", + "3" + ], + "defaultValue": "1", + "metadata": { + "description": "The size of the hosting plan (small, medium, or large)." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Location for all resources." + } + }, + "gitRepoUrl": { + "type": "string", + "metadata": { + "description": "The URL to the GitHub repository to deploy." + }, + "defaultValue": "https://github.com/OfficeDev/microsoft-teams-company-communicator-app.git" + }, + "gitBranch": { + "type": "string", + "metadata": { + "description": "The branch of the GitHub repository to deploy." + }, + "defaultValue": "master" + }, + "serviceBusWebAppRoleNameGuid": { + "defaultValue": "958380b3-630d-4823-b933-f59d92cdcada", + "minLength": 1, + "type": "String", + "metadata": { + "description": "A GUID used to identify the role assignment. This is Default value." + } + }, + "serviceBusPrepFuncRoleNameGuid": { + "defaultValue": "ce6ca916-08e9-4639-bfbe-9d098baf42ca", + "minLength": 1, + "type": "String", + "metadata": { + "description": "A GUID used to identify the role assignment. This is Default value." + } + }, + "serviceBusSendFuncRoleNameGuid": { + "defaultValue": "960365a2-c7bf-4ff3-8887-efa86fe4a163", + "minLength": 1, + "type": "String", + "metadata": { + "description": "A GUID used to identify the role assignment. This is Default value." + } + }, + "serviceBusDataFuncRoleNameGuid": { + "defaultValue": "d42703bc-421d-4d98-bc4d-cd2bb16e5b0a", + "minLength": 1, + "type": "String", + "metadata": { + "description": "A GUID used to identify the role assignment. This is Default value." + } + }, + "storageAccountWebAppRoleNameGuid": { + "defaultValue": "edd0cc48-2cf7-490e-99e8-131311e42030", + "minLength": 1, + "type": "String", + "metadata": { + "description": "A GUID used to identify the role assignment. This is Default value." + } + }, + "storageAccountPrepFuncRoleNameGuid": { + "defaultValue": "9332a9e9-93f4-48d9-8121-d279f30a732e", + "minLength": 1, + "type": "String", + "metadata": { + "description": "A GUID used to identify the role assignment. This is Default value." + } + }, + "storageAccountDataFuncRoleNameGuid": { + "defaultValue": "5b67af51-4a98-47e1-9d22-745069f51a13", + "minLength": 1, + "type": "String", + "metadata": { + "description": "A GUID used to identify the role assignment. This is Default value." + } + } + }, + "variables": { + "botName": "[parameters('baseResourceName')]", + "authorBotName": "[concat(parameters('baseResourceName'), '-author')]", + "botAppName": "[parameters('baseResourceName')]", + "botAppDomain": "[concat(variables('botAppName'), '.azurewebsites.net')]", + "botAppUrl": "[concat('https://', variables('botAppDomain'))]", + "hostingPlanName": "[parameters('baseResourceName')]", + "storageAccountName": "[uniquestring(concat(resourceGroup().id, parameters('baseResourceName')))]", + "appInsightsName": "[parameters('baseResourceName')]", + "prepFunctionAppName": "[concat(parameters('baseResourceName'), '-prep-function')]", + "sendFunctionAppName": "[concat(parameters('baseResourceName'), '-function')]", + "dataFunctionAppName": "[concat(parameters('baseResourceName'), '-data-function')]", + "serviceBusNamespaceName": "[parameters('baseResourceName')]", + "serviceBusSendQueueName": "company-communicator-send", + "serviceBusDataQueueName": "company-communicator-data", + "serviceBusPrepareToSendQueueName": "company-communicator-prep", + "serviceBusExportQueueName": "company-communicator-export", + "defaultSASKeyName": "RootManageSharedAccessKey", + "authRuleResourceId": "[resourceId('Microsoft.ServiceBus/namespaces/authorizationRules', variables('serviceBusNamespaceName'), variables('defaultSASKeyName'))]", + "sharedSkus": [ + "Free", + "Shared" + ], + "isSharedPlan": "[contains(variables('sharedSkus'), parameters('hostingPlanSku'))]", + "skuFamily": "[if(equals(parameters('hostingPlanSku'), 'Shared'), 'D', take(parameters('hostingPlanSku'), 1))]", + "useFrontDoor": "[equals(parameters('customDomainOption'), 'Azure Front Door')]", + "frontDoorName": "[parameters('baseResourceName')]", + "frontDoorDomain": "[toLower(concat(variables('frontDoorName'), '.azurefd.net'))]", + "ProactivelyInstallUserApp": "[parameters('ProactivelyInstallUserApp')]", + "UserAppExternalId": "[parameters('UserAppExternalId')]", + "i18n:DefaultCulture": "[parameters('DefaultCulture')]", + "i18n:SupportedCultures": "[parameters('SupportedCultures')]", + "AzureserviceBusDataOwner": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Authorization/roleDefinitions/', '090c5cfd-751d-490a-894a-3ce6f1109419')]", + "StorageBlobDataContributor": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Authorization/roleDefinitions/', 'ba92f5b4-2d11-453d-a403-e96b0029c9fe')]", + "keyvaultName": "[concat(variables('botAppName'), 'vault')]", + "keyVaultUrl": "[concat('https://',variables('keyvaultName'), '.vault.azure.net')]", + "subscriptionTenantId": "[subscription().tenantId]", + "StorageAccountSecretName": "[concat(variables('keyVaultName'), 'StorageAccountConnectionString')]", + "ServiceBusSecretName": "[concat(variables('keyVaultName'), 'ServiceBusConnectionString')]", + "AppInsightsSecretName": "[concat(variables('keyVaultName'),'AppInsightsKey')]", + "StorageAccountSecretResourceId": "[resourceId(resourceGroup().name, 'Microsoft.KeyVault/vaults/secrets', variables('keyVaultName'), variables('StorageAccountSecretName'))]", + "ServiceBusSecretResourceId": "[resourceId(resourceGroup().name, 'Microsoft.KeyVault/vaults/secrets', variables('keyVaultName'), variables('ServiceBusSecretName'))]", + "AppInsightsSecretResourceId": "[resourceId(resourceGroup().name, 'Microsoft.KeyVault/vaults/secrets', variables('keyVaultName'), variables('AppInsightsSecretName'))]" + }, + "resources": [ + { + "type": "Microsoft.Storage/storageAccounts", + "name": "[variables('storageAccountName')]", + "apiVersion": "2019-06-01", + "location": "[parameters('location')]", + "kind": "Storage", + "properties": { + "supportsHttpsTrafficOnly": true, + "allowBlobPublicAccess": false + }, + "sku": { + "name": "Standard_LRS" + } + }, + { + "type": "Microsoft.ServiceBus/namespaces", + "apiVersion": "2017-04-01", + "name": "[variables('serviceBusNamespaceName')]", + "location": "[parameters('location')]", + "sku": { + "name": "Basic", + "tier": "Basic" + }, + "resources": [ + { + "type": "Queues", + "apiVersion": "2017-04-01", + "name": "[variables('serviceBusSendQueueName')]", + "dependsOn": [ + "[concat('Microsoft.ServiceBus/namespaces/', variables('serviceBusNamespaceName'))]" + ], + "properties": { + "lockDuration": "PT5M", + "maxSizeInMegabytes": 1024, + "requiresDuplicateDetection": false, + "requiresSession": false, + "defaultMessageTimeToLive": "P14D", + "deadLetteringOnMessageExpiration": false, + "enableBatchedOperations": true, + "duplicateDetectionHistoryTimeWindow": "PT10M", + "maxDeliveryCount": 10, + "status": "Active", + "enablePartitioning": false, + "enableExpress": false + } + }, + { + "type": "Queues", + "apiVersion": "2017-04-01", + "name": "[variables('serviceBusDataQueueName')]", + "dependsOn": [ + "[concat('Microsoft.ServiceBus/namespaces/', variables('serviceBusNamespaceName'))]" + ], + "properties": { + "lockDuration": "PT5M", + "maxSizeInMegabytes": 1024, + "requiresDuplicateDetection": false, + "requiresSession": false, + "defaultMessageTimeToLive": "P14D", + "deadLetteringOnMessageExpiration": false, + "enableBatchedOperations": true, + "duplicateDetectionHistoryTimeWindow": "PT10M", + "maxDeliveryCount": 10, + "status": "Active", + "enablePartitioning": false, + "enableExpress": false + } + }, + { + "type": "Queues", + "apiVersion": "2017-04-01", + "name": "[variables('serviceBusPrepareToSendQueueName')]", + "dependsOn": [ + "[concat('Microsoft.ServiceBus/namespaces/', variables('serviceBusNamespaceName'))]" + ], + "properties": { + "lockDuration": "PT5M", + "maxSizeInMegabytes": 1024, + "requiresDuplicateDetection": false, + "requiresSession": false, + "defaultMessageTimeToLive": "P14D", + "deadLetteringOnMessageExpiration": false, + "enableBatchedOperations": true, + "duplicateDetectionHistoryTimeWindow": "PT10M", + "maxDeliveryCount": 10, + "status": "Active", + "enablePartitioning": false, + "enableExpress": false + } + }, + { + "type": "Queues", + "apiVersion": "2017-04-01", + "name": "[variables('serviceBusExportQueueName')]", + "dependsOn": [ + "[concat('Microsoft.ServiceBus/namespaces/', variables('serviceBusNamespaceName'))]" + ], + "properties": { + "lockDuration": "PT5M", + "maxSizeInMegabytes": 1024, + "requiresDuplicateDetection": false, + "requiresSession": false, + "defaultMessageTimeToLive": "P14D", + "deadLetteringOnMessageExpiration": false, + "enableBatchedOperations": true, + "duplicateDetectionHistoryTimeWindow": "PT10M", + "maxDeliveryCount": 10, + "status": "Active", + "enablePartitioning": false, + "enableExpress": false + } + } + ] + }, + { + "type": "Microsoft.Web/serverfarms", + "apiVersion": "2016-09-01", + "name": "[variables('hostingPlanName')]", + "location": "[parameters('location')]", + "properties": { + "name": "[variables('hostingPlanName')]", + "hostingEnvironment": "", + "numberOfWorkers": 1 + }, + "sku": { + "name": "[if(variables('isSharedPlan'), concat(variables('skuFamily'), '1'), concat(variables('skuFamily'), parameters('hostingPlanSize')))]", + "tier": "[parameters('hostingPlanSku')]", + "size": "[concat(variables('skuFamily'), parameters('hostingPlanSize'))]", + "family": "[variables('skuFamily')]", + "capacity": 0 + } + }, + { + "apiVersion": "2015-05-01", + "name": "[variables('appInsightsName')]", + "type": "Microsoft.Insights/components", + "location": "[parameters('location')]", + "tags": { + "[concat('hidden-link:', resourceGroup().id, '/providers/Microsoft.Web/sites/', variables('botAppName'))]": "Resource" + }, + "properties": { + "Application_Type": "web", + "Request_Source": "rest" + } + }, + { + "apiVersion": "2018-07-12", + "name": "[variables('authorBotName')]", + "type": "Microsoft.BotService/botServices", + "location": "global", + "sku": { + "name": "F0" + }, + "kind": "sdk", + "properties": { + "displayName": "[concat(parameters('appDisplayName'),'-author')]", + "description": "[parameters('appDescription')]", + "iconUrl": "[parameters('appIconUrl')]", + "msaAppId": "[parameters('authorClientId')]", + "endpoint": "[concat(variables('botAppUrl'), '/api/messages/author')]", + "developerAppInsightKey": "[reference(resourceId('Microsoft.Insights/components', variables('appInsightsName')), '2015-05-01').InstrumentationKey]" + }, + "resources": [ + { + "name": "[concat(variables('authorBotName'), '/MsTeamsChannel')]", + "type": "Microsoft.BotService/botServices/channels", + "apiVersion": "2018-07-12", + "location": "global", + "sku": { + "name": "F0" + }, + "properties": { + "channelName": "MsTeamsChannel", + "location": "global", + "properties": { + "isEnabled": true + } + }, + "dependsOn": [ + "[concat('Microsoft.BotService/botServices/', variables('authorBotName'))]" + ] + } + ] + }, + { + "apiVersion": "2018-07-12", + "name": "[variables('botName')]", + "type": "Microsoft.BotService/botServices", + "location": "global", + "sku": { + "name": "F0" + }, + "kind": "sdk", + "properties": { + "displayName": "[parameters('appDisplayName')]", + "description": "[parameters('appDescription')]", + "iconUrl": "[parameters('appIconUrl')]", + "msaAppId": "[parameters('userClientId')]", + "endpoint": "[concat(variables('botAppUrl'), '/api/messages/user')]", + "developerAppInsightKey": "[reference(resourceId('Microsoft.Insights/components', variables('appInsightsName')), '2015-05-01').InstrumentationKey]" + }, + "resources": [ + { + "name": "[concat(variables('botName'), '/MsTeamsChannel')]", + "type": "Microsoft.BotService/botServices/channels", + "apiVersion": "2018-07-12", + "location": "global", + "sku": { + "name": "F0" + }, + "properties": { + "channelName": "MsTeamsChannel", + "location": "global", + "properties": { + "isEnabled": true + } + }, + "dependsOn": [ + "[concat('Microsoft.BotService/botServices/', variables('botName'))]" + ] + } + ] + }, + { + "apiVersion": "2016-08-01", + "type": "Microsoft.Web/sites", + "name": "[variables('botAppName')]", + "location": "[parameters('location')]", + "kind": "app", + "identity": { + "type": "SystemAssigned" + }, + "properties": { + "name": "[variables('botAppName')]", + "serverFarmId": "[resourceId('Microsoft.Web/serverfarms', variables('hostingPlanName'))]", + "enabled": true, + "reserved": false, + "clientAffinityEnabled": true, + "clientCertEnabled": false, + "hostNamesDisabled": false, + "containerSize": 0, + "dailyMemoryTimeQuota": 0, + "httpsOnly": true, + "siteConfig": { + "ftpsState": "Disabled", + "alwaysOn": "[not(variables('isSharedPlan'))]", + "cors": { + "supportCredentials": true, + "allowedOrigins": [ + "[concat('https://', variables('frontDoorDomain'))]" + ] + } + } + }, + "dependsOn": [ + "[resourceId('Microsoft.Web/serverfarms', variables('hostingPlanName'))]", + "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]", + "[resourceId('Microsoft.Insights/components', variables('appInsightsName'))]", + "[resourceId('Microsoft.ServiceBus/namespaces', variables('serviceBusNamespaceName'))]", + "[resourceId('Microsoft.Web/sites', variables('prepFunctionAppName'))]", + "[resourceId('Microsoft.Web/sites', variables('sendFunctionAppName'))]", + "[resourceId('Microsoft.Web/sites', variables('dataFunctionAppName'))]" + ], + "resources": [ + { + "apiVersion": "2015-08-01", + "name": "appsettings", + "type": "config", + "dependsOn": [ + "[resourceId('Microsoft.Web/sites', variables('botAppName'))]", + "[resourceId('Microsoft.KeyVault/vaults/', variables('keyVaultName'))]", + "[resourceId('Microsoft.KeyVault/vaults/secrets', variables('keyVaultName'), variables('StorageAccountSecretName'))]", + "[resourceId('Microsoft.KeyVault/vaults/secrets', variables('keyVaultName'), variables('ServiceBusSecretName'))]" + ], + "properties": { + "PROJECT": "Source/CompanyCommunicator/Microsoft.Teams.Apps.CompanyCommunicator.csproj", + "SITE_ROLE": "app", + "i18n:DefaultCulture": "[variables('i18n:DefaultCulture')]", + "i18n:SupportedCultures": "[variables('i18n:SupportedCultures')]", + "ProactivelyInstallUserApp": "[variables('ProactivelyInstallUserApp')]", + "UserAppExternalId": "[variables('UserAppExternalId')]", + "AzureAd:TenantId": "[parameters('tenantId')]", + "AzureAd:ClientId": "[parameters('graphAppId')]", + "AzureAd:ClientSecret": "", + "AzureAd:ApplicationIdURI": "[if(variables('useFrontDoor'), concat('api://', variables('frontDoorDomain')), '')]", + "UserAppId": "[parameters('userClientId')]", + "UserAppCertName": "[parameters('userAppCertName')]", + "AuthorAppId": "[parameters('authorClientId')]", + "AuthorAppCertName": "[parameters('authorAppCertName')]", + "GraphAppId": "[parameters('graphAppId')]", + "GraphAppCertName": "[parameters('graphAppCertName')]", + "StorageAccountConnectionString": "[concat('@Microsoft.KeyVault(SecretUri=', reference(variables('StorageAccountSecretResourceId'),'2015-06-01').secretUriWithVersion, ')')]", + "ServiceBusConnection": "[concat('@Microsoft.KeyVault(SecretUri=', reference(variables('ServiceBusSecretResourceId'),'2015-06-01').secretUriWithVersion, ')')]", + "ServiceBusNamespace": "[concat(variables('serviceBusNamespaceName'),'.servicebus.windows.net')]", + "StorageAccountName": "[variables('storageAccountName')]", + "UseManagedIdentity": "true", + "AllowedTenants": "[parameters('tenantId')]", + "DisableTenantFilter": "false", + "AuthorizedCreatorUpns": "[parameters('senderUPNList')]", + "UseCertificate": "true", + "DisableAuthentication": "false", + "DisableCreatorUpnCheck": "false", + "WEBSITE_LOAD_CERTIFICATES": "*", + "APPINSIGHTS_INSTRUMENTATIONKEY": "[concat('@Microsoft.KeyVault(SecretUri=', reference(variables('AppInsightsSecretResourceId'), '2015-06-01').secretUriWithVersion, ')')]", + "WEBSITE_NODE_DEFAULT_VERSION": "10.15.2", + "KeyVault:Url": "[variables('keyVaultUrl')]", + "DOTNET_ADD_GLOBAL_TOOLS_TO_PATH": "false" + } + }, + { + "apiVersion": "2016-08-01", + "name": "web", + "type": "sourcecontrols", + "condition": "[not(empty(parameters('gitRepoUrl')))]", + "dependsOn": [ + "[resourceId('Microsoft.Web/sites', variables('botAppName'))]", + "[resourceId('Microsoft.Web/sites/config', variables('botAppName'), 'appsettings')]" + ], + "properties": { + "RepoUrl": "[parameters('gitRepoUrl')]", + "branch": "[parameters('gitBranch')]", + "IsManualIntegration": true + } + } + ] + }, + { + "apiVersion": "2016-08-01", + "type": "Microsoft.Web/sites", + "name": "[variables('prepFunctionAppName')]", + "location": "[parameters('location')]", + "kind": "functionapp", + "identity": { + "type": "SystemAssigned" + }, + "properties": { + "name": "[variables('prepFunctionAppName')]", + "serverFarmId": "[resourceId('Microsoft.Web/serverfarms', variables('hostingPlanName'))]", + "hostingEnvironment": "", + "clientAffinityEnabled": false, + "httpsOnly": true, + "siteConfig": { + "ftpsState": "Disabled", + "alwaysOn": "[not(variables('isSharedPlan'))]" + } + }, + "dependsOn": [ + "[resourceId('Microsoft.Web/serverfarms', variables('hostingPlanName'))]", + "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]", + "[resourceId('Microsoft.ServiceBus/namespaces', variables('serviceBusNamespaceName'))]" + ], + "resources": [ + { + "apiVersion": "2015-08-01", + "name": "appsettings", + "type": "config", + "dependsOn": [ + "[resourceId('Microsoft.Web/sites', variables('prepFunctionAppName'))]", + "[resourceId('Microsoft.KeyVault/vaults/', variables('keyVaultName'))]", + "[resourceId('Microsoft.KeyVault/vaults/secrets', variables('keyVaultName'), variables('StorageAccountSecretName'))]", + "[resourceId('Microsoft.KeyVault/vaults/secrets', variables('keyVaultName'), variables('ServiceBusSecretName'))]" + ], + "properties": { + "PROJECT": "Source\\CompanyCommunicator.Prep.Func\\Microsoft.Teams.Apps.CompanyCommunicator.Prep.Func.csproj", + "SITE_ROLE": "function", + "i18n:DefaultCulture": "[variables('i18n:DefaultCulture')]", + "i18n:SupportedCultures": "[variables('i18n:SupportedCultures')]", + "ProactivelyInstallUserApp": "[variables('ProactivelyInstallUserApp')]", + "UserAppExternalId": "[variables('UserAppExternalId')]", + "TenantId": "[parameters('tenantId')]", + "UserAppId": "[parameters('userClientId')]", + "UserAppCertName": "[parameters('userAppCertName')]", + "AuthorAppId": "[parameters('authorClientId')]", + "AuthorAppCertName": "[parameters('authorAppCertName')]", + "GraphAppId": "[parameters('graphAppId')]", + "GraphAppCertName": "[parameters('graphAppCertName')]", + "StorageAccountConnectionString": "[concat('@Microsoft.KeyVault(SecretUri=', reference(variables('StorageAccountSecretResourceId'),'2015-06-01').secretUriWithVersion, ')')]", + "ServiceBusConnection": "[concat('@Microsoft.KeyVault(SecretUri=', reference(variables('ServiceBusSecretResourceId'),'2015-06-01').secretUriWithVersion, ')')]", + "ServiceBusNamespace": "[concat(variables('serviceBusNamespaceName'),'.servicebus.windows.net')]", + "StorageAccountName": "[variables('storageAccountName')]", + "UseManagedIdentity": "true", + "UseCertificate": "true", + "WEBSITE_LOAD_CERTIFICATES": "*", + "APPINSIGHTS_INSTRUMENTATIONKEY": "[concat('@Microsoft.KeyVault(SecretUri=', reference(variables('AppInsightsSecretResourceId'), '2015-06-01').secretUriWithVersion, ')')]", + "KeyVault:Url": "[variables('keyVaultUrl')]", + "AzureWebJobsStorage": "[concat('DefaultEndpointsProtocol=https;AccountName=', variables('storageAccountName'), ';AccountKey=', listKeys(resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName')),'2015-05-01-preview').key1)]", + "AzureWebJobsDashboard": "[concat('@Microsoft.KeyVault(SecretUri=', reference(variables('StorageAccountSecretResourceId'),'2015-06-01').secretUriWithVersion, ')')]", + "FUNCTIONS_EXTENSION_VERSION": "~3", + "FUNCTIONS_WORKER_RUNTIME": "dotnet", + "WEBSITE_CONTENTAZUREFILECONNECTIONSTRING": "[concat('DefaultEndpointsProtocol=https;AccountName=', variables('storageAccountName'), ';AccountKey=', listKeys(resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName')),'2015-05-01-preview').key1)]", + "WEBSITE_CONTENTSHARE": "[toLower(variables('prepFunctionAppName'))]", + "AzureFunctionsJobHost__extensions__durableTask__maxConcurrentOrchestratorFunctions": "3", + "AzureFunctionsJobHost__extensions__durableTask__maxConcurrentActivityFunctions": "10", + "DOTNET_ADD_GLOBAL_TOOLS_TO_PATH": "false", + "WEBSITE_NODE_DEFAULT_VERSION": "10.15.2" + } + }, + { + "apiVersion": "2015-08-01", + "name": "web", + "type": "sourcecontrols", + "condition": "[not(empty(parameters('gitRepoUrl')))]", + "dependsOn": [ + "[resourceId('Microsoft.Web/sites', variables('prepFunctionAppName'))]", + "[resourceId('Microsoft.Web/sites/config', variables('prepFunctionAppName'), 'appsettings')]" + ], + "properties": { + "RepoUrl": "[parameters('gitRepoUrl')]", + "branch": "[parameters('gitBranch')]", + "IsManualIntegration": true + } + } + ] + }, + { + "apiVersion": "2016-08-01", + "type": "Microsoft.Web/sites", + "name": "[variables('sendFunctionAppName')]", + "location": "[parameters('location')]", + "kind": "functionapp", + "identity": { + "type": "SystemAssigned" + }, + "properties": { + "name": "[variables('sendFunctionAppName')]", + "serverFarmId": "[resourceId('Microsoft.Web/serverfarms', variables('hostingPlanName'))]", + "hostingEnvironment": "", + "clientAffinityEnabled": false, + "httpsOnly": true, + "siteConfig": { + "ftpsState": "Disabled", + "alwaysOn": "[not(variables('isSharedPlan'))]" + } + }, + "dependsOn": [ + "[resourceId('Microsoft.Web/serverfarms', variables('hostingPlanName'))]", + "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]", + "[resourceId('Microsoft.ServiceBus/namespaces', variables('serviceBusNamespaceName'))]" + ], + "resources": [ + { + "apiVersion": "2015-08-01", + "name": "appsettings", + "type": "config", + "dependsOn": [ + "[resourceId('Microsoft.Web/sites', variables('sendFunctionAppName'))]", + "[resourceId('Microsoft.KeyVault/vaults/', variables('keyVaultName'))]", + "[resourceId('Microsoft.KeyVault/vaults/secrets', variables('keyVaultName'), variables('StorageAccountSecretName'))]", + "[resourceId('Microsoft.KeyVault/vaults/secrets', variables('keyVaultName'), variables('ServiceBusSecretName'))]" + ], + "properties": { + "PROJECT": "Source\\CompanyCommunicator.Send.Func\\Microsoft.Teams.Apps.CompanyCommunicator.Send.Func.csproj", + "SITE_ROLE": "function", + "i18n:DefaultCulture": "[variables('i18n:DefaultCulture')]", + "i18n:SupportedCultures": "[variables('i18n:SupportedCultures')]", + "ProactivelyInstallUserApp": "[variables('ProactivelyInstallUserApp')]", + "UserAppId": "[parameters('userClientId')]", + "UserAppCertName": "[parameters('userAppCertName')]", + "AuthorAppId": "[parameters('authorClientId')]", + "AuthorAppCertName": "[parameters('authorAppCertName')]", + "GraphAppId": "[parameters('graphAppId')]", + "GraphAppCertName": "[parameters('graphAppCertName')]", + "StorageAccountConnectionString": "[concat('@Microsoft.KeyVault(SecretUri=', reference(variables('StorageAccountSecretResourceId'),'2015-06-01').secretUriWithVersion, ')')]", + "ServiceBusConnection": "[concat('@Microsoft.KeyVault(SecretUri=', reference(variables('ServiceBusSecretResourceId'),'2015-06-01').secretUriWithVersion, ')')]", + "ServiceBusNamespace": "[concat(variables('serviceBusNamespaceName'),'.servicebus.windows.net')]", + "StorageAccountName": "[variables('storageAccountName')]", + "UseManagedIdentity": "true", + "UseCertificate": "true", + "WEBSITE_LOAD_CERTIFICATES": "*", + "MaxNumberOfAttempts": "5", + "APPINSIGHTS_INSTRUMENTATIONKEY": "[concat('@Microsoft.KeyVault(SecretUri=', reference(variables('AppInsightsSecretResourceId'), '2015-06-01').secretUriWithVersion, ')')]", + "KeyVault:Url": "[variables('keyVaultUrl')]", + "AzureWebJobsStorage": "[concat('DefaultEndpointsProtocol=https;AccountName=', variables('storageAccountName'), ';AccountKey=', listKeys(resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName')),'2015-05-01-preview').key1)]", + "AzureWebJobsDashboard": "[concat('@Microsoft.KeyVault(SecretUri=', reference(variables('StorageAccountSecretResourceId'),'2015-06-01').secretUriWithVersion, ')')]", + "FUNCTIONS_EXTENSION_VERSION": "~3", + "FUNCTIONS_WORKER_RUNTIME": "dotnet", + "WEBSITE_CONTENTAZUREFILECONNECTIONSTRING": "[concat('DefaultEndpointsProtocol=https;AccountName=', variables('storageAccountName'), ';AccountKey=', listKeys(resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName')),'2015-05-01-preview').key1)]", + "WEBSITE_CONTENTSHARE": "[toLower(variables('sendFunctionAppName'))]", + "DOTNET_ADD_GLOBAL_TOOLS_TO_PATH": "false", + "WEBSITE_NODE_DEFAULT_VERSION": "10.15.2" + } + }, + { + "apiVersion": "2015-08-01", + "name": "web", + "type": "sourcecontrols", + "condition": "[not(empty(parameters('gitRepoUrl')))]", + "dependsOn": [ + "[resourceId('Microsoft.Web/sites', variables('sendFunctionAppName'))]", + "[resourceId('Microsoft.Web/sites/config', variables('sendFunctionAppName'), 'appsettings')]" + ], + "properties": { + "RepoUrl": "[parameters('gitRepoUrl')]", + "branch": "[parameters('gitBranch')]", + "IsManualIntegration": true + } + } + ] + }, + { + "apiVersion": "2016-08-01", + "type": "Microsoft.Web/sites", + "name": "[variables('dataFunctionAppName')]", + "location": "[parameters('location')]", + "kind": "functionapp", + "identity": { + "type": "SystemAssigned" + }, + "properties": { + "name": "[variables('dataFunctionAppName')]", + "serverFarmId": "[resourceId('Microsoft.Web/serverfarms', variables('hostingPlanName'))]", + "hostingEnvironment": "", + "clientAffinityEnabled": false, + "httpsOnly": true, + "siteConfig": { + "ftpsState": "Disabled", + "alwaysOn": "[not(variables('isSharedPlan'))]" + } + }, + "dependsOn": [ + "[resourceId('Microsoft.Web/serverfarms', variables('hostingPlanName'))]", + "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]", + "[resourceId('Microsoft.ServiceBus/namespaces', variables('serviceBusNamespaceName'))]" + ], + "resources": [ + { + "apiVersion": "2015-08-01", + "name": "appsettings", + "type": "config", + "dependsOn": [ + "[resourceId('Microsoft.Web/sites', variables('dataFunctionAppName'))]", + "[resourceId('Microsoft.KeyVault/vaults/', variables('keyVaultName'))]", + "[resourceId('Microsoft.KeyVault/vaults/secrets', variables('keyVaultName'), variables('StorageAccountSecretName'))]", + "[resourceId('Microsoft.KeyVault/vaults/secrets', variables('keyVaultName'), variables('ServiceBusSecretName'))]" + ], + "properties": { + "PROJECT": "Source\\CompanyCommunicator.Data.Func\\Microsoft.Teams.Apps.CompanyCommunicator.Data.Func.csproj", + "SITE_ROLE": "function", + "i18n:DefaultCulture": "[variables('i18n:DefaultCulture')]", + "i18n:SupportedCultures": "[variables('i18n:SupportedCultures')]", + "ProactivelyInstallUserApp": "[variables('ProactivelyInstallUserApp')]", + "UserAppId": "[parameters('userClientId')]", + "UserAppCertName": "[parameters('userAppCertName')]", + "AuthorAppId": "[parameters('authorClientId')]", + "AuthorAppCertName": "[parameters('authorAppCertName')]", + "GraphAppId": "[parameters('graphAppId')]", + "GraphAppCertName": "[parameters('graphAppCertName')]", + "StorageAccountConnectionString": "[concat('@Microsoft.KeyVault(SecretUri=', reference(variables('StorageAccountSecretResourceId'),'2015-06-01').secretUriWithVersion, ')')]", + "ServiceBusConnection": "[concat('@Microsoft.KeyVault(SecretUri=', reference(variables('ServiceBusSecretResourceId'),'2015-06-01').secretUriWithVersion, ')')]", + "ServiceBusNamespace": "[concat(variables('serviceBusNamespaceName'),'.servicebus.windows.net')]", + "StorageAccountName": "[variables('storageAccountName')]", + "UseManagedIdentity": "true", + "UseCertificate": "true", + "WEBSITE_LOAD_CERTIFICATES": "*", + "APPINSIGHTS_INSTRUMENTATIONKEY": "[concat('@Microsoft.KeyVault(SecretUri=', reference(variables('AppInsightsSecretResourceId'), '2015-06-01').secretUriWithVersion, ')')]", + "KeyVault:Url": "[variables('keyVaultUrl')]", + "AzureWebJobsStorage": "[concat('DefaultEndpointsProtocol=https;AccountName=', variables('storageAccountName'), ';AccountKey=', listKeys(resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName')),'2015-05-01-preview').key1)]", + "AzureWebJobsDashboard": "[concat('@Microsoft.KeyVault(SecretUri=', reference(variables('StorageAccountSecretResourceId'),'2015-06-01').secretUriWithVersion, ')')]", + "FUNCTIONS_EXTENSION_VERSION": "~3", + "FUNCTIONS_WORKER_RUNTIME": "dotnet", + "WEBSITE_CONTENTAZUREFILECONNECTIONSTRING": "[concat('DefaultEndpointsProtocol=https;AccountName=', variables('storageAccountName'), ';AccountKey=', listKeys(resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName')),'2015-05-01-preview').key1)]", + "WEBSITE_CONTENTSHARE": "[toLower(variables('dataFunctionAppName'))]", + "CleanUpScheduleTriggerTime": "30 23 * * *", + "CleanUpFile": "1", + "DOTNET_ADD_GLOBAL_TOOLS_TO_PATH": "false", + "WEBSITE_NODE_DEFAULT_VERSION": "10.15.2" + } + }, + { + "apiVersion": "2015-08-01", + "name": "web", + "type": "sourcecontrols", + "condition": "[not(empty(parameters('gitRepoUrl')))]", + "dependsOn": [ + "[resourceId('Microsoft.Web/sites', variables('dataFunctionAppName'))]", + "[resourceId('Microsoft.Web/sites/config', variables('dataFunctionAppName'), 'appsettings')]" + ], + "properties": { + "RepoUrl": "[parameters('gitRepoUrl')]", + "branch": "[parameters('gitBranch')]", + "IsManualIntegration": true + } + } + ] + }, + { + "type": "Microsoft.KeyVault/vaults", + "name": "[variables('keyvaultName')]", + "apiVersion": "2016-10-01", + "location": "[parameters('location')]", + "tags": { + "displayName": "KeyVault" + }, + "dependsOn": [ + "[resourceId('Microsoft.Web/sites', variables('botAppName'))]", + "[resourceId('Microsoft.Web/sites', variables('prepFunctionAppName'))]", + "[resourceId('Microsoft.Web/sites', variables('sendFunctionAppName'))]", + "[resourceId('Microsoft.Web/sites', variables('dataFunctionAppName'))]" + ], + "properties": { + "tenantId": "[variables('subscriptionTenantId')]", + "accessPolicies": [ + { + "tenantId": "[reference(concat('Microsoft.Web/sites/', variables('botAppName')), '2018-02-01', 'Full').identity.tenantId]", + "objectId": "[reference(concat('Microsoft.Web/sites/', variables('botAppName')), '2018-02-01', 'Full').identity.principalId]", + "permissions": { + "keys": [], + "secrets": [ + "Get", + "Set", + "Restore" + ], + "certificates": [ + "Get" + ] + } + }, + { + "tenantId": "[reference(concat('Microsoft.Web/sites/', variables('prepFunctionAppName')), '2018-02-01', 'Full').identity.tenantId]", + "objectId": "[reference(concat('Microsoft.Web/sites/', variables('prepFunctionAppName')), '2018-02-01', 'Full').identity.principalId]", + "permissions": { + "keys": [], + "secrets": [ + "Get" + ], + "certificates": [ + "Get" + ] + } + }, + { + "tenantId": "[reference(concat('Microsoft.Web/sites/', variables('sendFunctionAppName')), '2018-02-01', 'Full').identity.tenantId]", + "objectId": "[reference(concat('Microsoft.Web/sites/', variables('sendFunctionAppName')), '2018-02-01', 'Full').identity.principalId]", + "permissions": { + "keys": [], + "secrets": [ + "Get" + ], + "certificates": [ + "Get" + ] + } + }, + { + "tenantId": "[reference(concat('Microsoft.Web/sites/', variables('dataFunctionAppName')), '2018-02-01', 'Full').identity.tenantId]", + "objectId": "[reference(concat('Microsoft.Web/sites/', variables('dataFunctionAppName')), '2018-02-01', 'Full').identity.principalId]", + "permissions": { + "keys": [], + "secrets": [ + "Get" + ], + "certificates": [ + "Get" + ] + } + }, + { + "tenantId": "[reference(concat('Microsoft.Web/sites/', variables('botAppName')), '2018-02-01', 'Full').identity.tenantId]", + "objectId": "[parameters('objectId')]", + "permissions": { + "certificates": [ "get", "list", "create", "update" ] + } + } + ], + "sku": { + "name": "Standard", + "family": "A" + }, + "networkAcls": { + "bypass": "AzureServices", + "defaultAction": "Allow" + } + }, + "resources": [ + { + "type": "secrets", + "apiVersion": "2016-10-01", + "name": "[variables('StorageAccountSecretName')]", + "location": "[parameters('location')]", + "dependsOn": [ + "[resourceId('Microsoft.KeyVault/vaults', variables('keyVaultName'))]", + "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]" + ], + "properties": { + "value": "[concat('DefaultEndpointsProtocol=https;AccountName=', variables('storageAccountName'), ';AccountKey=', listKeys(resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName')),'2015-05-01-preview').key1)]", + "attributes": { + "enabled": true + } + } + }, + { + "type": "secrets", + "apiVersion": "2016-10-01", + "name": "[variables('ServiceBusSecretName')]", + "location": "[parameters('location')]", + "dependsOn": [ + "[resourceId('Microsoft.KeyVault/vaults', variables('keyVaultName'))]", + "[resourceId('Microsoft.ServiceBus/namespaces', variables('serviceBusNamespaceName'))]" + ], + "properties": { + "value": "[listkeys(variables('authRuleResourceId'), '2017-04-01').primaryConnectionString]", + "attributes": { + "enabled": true + } + } + }, + { + "type": "secrets", + "name": "[variables('AppInsightsSecretName')]", + "location": "[parameters('location')]", + "apiVersion": "2018-02-14", + "dependsOn": [ + "[resourceId('Microsoft.KeyVault/vaults/', variables('keyVaultName'))]", + "[resourceId('Microsoft.Insights/components', variables('appInsightsName'))]" + ], + "properties": { + "value": "[reference(resourceId('Microsoft.Insights/components/', variables('appInsightsName')), '2015-05-01').InstrumentationKey]", + "attributes": { + "enabled": true + } + } + } + ] + }, + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2020-04-01-preview", + "name": "[parameters('ServiceBusWebAppRoleNameGuid')]", + "scope": "[concat('Microsoft.ServiceBus/namespaces', '/', variables('serviceBusNamespaceName'))]", + "dependsOn": [ + "[resourceId('Microsoft.ServiceBus/namespaces', variables('serviceBusNamespaceName'))]", + "[resourceId('Microsoft.Web/sites', variables('botAppName'))]" + ], + "properties": { + "roleDefinitionId": "[variables('AzureserviceBusDataOwner')]", + "principalId": "[reference(resourceId('Microsoft.Web/sites', variables('botAppName')), '2019-08-01', 'Full').identity.principalId]", + "principalType": "ServicePrincipal" + } + }, + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2020-04-01-preview", + "name": "[parameters('ServiceBusPrepFuncRoleNameGuid')]", + "scope": "[concat('Microsoft.ServiceBus/namespaces', '/', variables('serviceBusNamespaceName'))]", + "dependsOn": [ + "[resourceId('Microsoft.ServiceBus/namespaces', variables('serviceBusNamespaceName'))]", + "[resourceId('Microsoft.Web/sites', variables('prepFunctionAppName'))]" + ], + "properties": { + "roleDefinitionId": "[variables('AzureserviceBusDataOwner')]", + "principalId": "[reference(resourceId('Microsoft.Web/sites', variables('prepFunctionAppName')), '2019-08-01', 'Full').identity.principalId]", + "principalType": "ServicePrincipal" + } + }, + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2020-04-01-preview", + "name": "[parameters('ServiceBusSendFuncRoleNameGuid')]", + "scope": "[concat('Microsoft.ServiceBus/namespaces', '/', variables('serviceBusNamespaceName'))]", + "dependsOn": [ + "[resourceId('Microsoft.ServiceBus/namespaces', variables('serviceBusNamespaceName'))]", + "[resourceId('Microsoft.Web/sites', variables('sendFunctionAppName'))]" + ], + "properties": { + "roleDefinitionId": "[variables('AzureserviceBusDataOwner')]", + "principalId": "[reference(resourceId('Microsoft.Web/sites', variables('sendFunctionAppName')), '2019-08-01', 'Full').identity.principalId]", + "principalType": "ServicePrincipal" + } + }, + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2020-04-01-preview", + "name": "[parameters('ServiceBusDataFuncRoleNameGuid')]", + "scope": "[concat('Microsoft.ServiceBus/namespaces', '/', variables('serviceBusNamespaceName'))]", + "dependsOn": [ + "[resourceId('Microsoft.ServiceBus/namespaces', variables('serviceBusNamespaceName'))]", + "[resourceId('Microsoft.Web/sites', variables('dataFunctionAppName'))]" + ], + "properties": { + "roleDefinitionId": "[variables('AzureserviceBusDataOwner')]", + "principalId": "[reference(resourceId('Microsoft.Web/sites', variables('dataFunctionAppName')), '2019-08-01', 'Full').identity.principalId]", + "principalType": "ServicePrincipal" + } + }, + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2020-04-01-preview", + "name": "[parameters('StorageAccountWebAppRoleNameGuid')]", + "scope": "[concat('Microsoft.Storage/storageAccounts', '/', variables('storageAccountName'))]", + "dependsOn": [ + "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]", + "[resourceId('Microsoft.Web/sites', variables('botAppName'))]" + ], + "properties": { + "roleDefinitionId": "[variables('StorageBlobDataContributor')]", + "principalId": "[reference(resourceId('Microsoft.Web/sites', variables('botAppName')), '2019-08-01', 'Full').identity.principalId]", + "principalType": "ServicePrincipal" + } + }, + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2020-04-01-preview", + "name": "[parameters('StorageAccountPrepFuncRoleNameGuid')]", + "scope": "[concat('Microsoft.Storage/storageAccounts', '/', variables('storageAccountName'))]", + "dependsOn": [ + "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]", + "[resourceId('Microsoft.Web/sites', variables('prepFunctionAppName'))]" + ], + "properties": { + "roleDefinitionId": "[variables('StorageBlobDataContributor')]", + "principalId": "[reference(resourceId('Microsoft.Web/sites', variables('prepFunctionAppName')), '2019-08-01', 'Full').identity.principalId]", + "principalType": "ServicePrincipal" + } + }, + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2020-04-01-preview", + "name": "[parameters('StorageAccountDataFuncRoleNameGuid')]", + "scope": "[concat('Microsoft.Storage/storageAccounts', '/', variables('storageAccountName'))]", + "dependsOn": [ + "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]", + "[resourceId('Microsoft.Web/sites', variables('dataFunctionAppName'))]" + ], + "properties": { + "roleDefinitionId": "[variables('StorageBlobDataContributor')]", + "principalId": "[reference(resourceId('Microsoft.Web/sites', variables('dataFunctionAppName')), '2019-08-01', 'Full').identity.principalId]", + "principalType": "ServicePrincipal" + } + }, + { + "apiVersion": "2019-04-01", + "type": "Microsoft.Network/frontDoors", + "name": "[variables('frontDoorName')]", + "condition": "[variables('useFrontDoor')]", + "location": "Global", + "dependsOn": [ + "[resourceId('Microsoft.Web/sites', variables('botAppName'))]" + ], + "properties": { + "backendPools": [ + { + "name": "backendPool1", + "properties": { + "backends": [ + { + "address": "[variables('botAppDomain')]", + "backendHostHeader": "[variables('botAppDomain')]", + "httpPort": 80, + "httpsPort": 443, + "priority": 1, + "weight": 50, + "enabledState": "Enabled" + } + ], + "healthProbeSettings": { + "id": "[resourceId('Microsoft.Network/frontDoors/healthProbeSettings', variables('frontDoorName'), 'healthProbeSettings1')]" + }, + "loadBalancingSettings": { + "id": "[resourceId('Microsoft.Network/frontDoors/loadBalancingSettings', variables('frontDoorName'), 'loadBalancingSettings1')]" + }, + "resourceState": "Enabled" + } + } + ], + "healthProbeSettings": [ + { + "name": "healthProbeSettings1", + "properties": { + "intervalInSeconds": 255, + "path": "/health", + "protocol": "Https", + "resourceState": "Enabled" + } + } + ], + "frontendEndpoints": [ + { + "name": "frontendEndpoint1", + "properties": { + "hostName": "[variables('frontDoorDomain')]", + "sessionAffinityEnabledState": "Disabled", + "sessionAffinityTtlSeconds": 0 + } + } + ], + "loadBalancingSettings": [ + { + "name": "loadBalancingSettings1", + "properties": { + "additionalLatencyMilliseconds": 0, + "sampleSize": 4, + "successfulSamplesRequired": 2 + } + } + ], + "routingRules": [ + { + "name": "routingRule1", + "properties": { + "frontendEndpoints": [ + { + "id": "[resourceId('Microsoft.Network/frontDoors/frontendEndpoints', variables('frontDoorName'), 'frontendEndpoint1')]" + } + ], + "acceptedProtocols": [ + "Https" + ], + "patternsToMatch": [ + "/*" + ], + "routeConfiguration": { + "@odata.type": "#Microsoft.Azure.FrontDoor.Models.FrontdoorForwardingConfiguration", + "forwardingProtocol": "HttpsOnly", + "backendPool": { + "id": "[resourceId('Microsoft.Network/frontDoors/backendPools', variables('frontDoorName'), 'backendPool1')]" + } + }, + "enabledState": "Enabled" + } + }, + { + "name": "routingRule2", + "properties": { + "frontendEndpoints": [ + { + "id": "[resourceId('Microsoft.Network/frontDoors/frontendEndpoints', variables('frontDoorName'), 'frontendEndpoint1')]" + } + ], + "acceptedProtocols": [ + "Https" + ], + "patternsToMatch": [ + "/api/*" + ], + "routeConfiguration": { + "@odata.type": "#Microsoft.Azure.FrontDoor.Models.FrontdoorRedirectConfiguration", + "customFragment": null, + "customHost": "[variables('botAppDomain')]", + "customPath": "", + "redirectProtocol": "HttpsOnly", + "customQueryString": null, + "redirectType": "PermanentRedirect" + }, + "enabledState": "Enabled" + } + } + ], + "enabledState": "Enabled", + "friendlyName": "[variables('frontDoorName')]" + } + } + ], + "outputs": { + "keyVaultName": { + "type": "string", + "value": "[variables('keyvaultName')]" + }, + "authorBotId": { + "type": "string", + "value": "[parameters('authorClientId')]" + }, + "userBotId": { + "type": "string", + "value": "[parameters('userClientId')]" + }, + "appDomain": { + "type": "string", + "value": "[if(variables('useFrontDoor'), variables('frontDoorDomain'), concat('Please create a custom domain name for ', variables('botAppDomain'), ' and use that in the manifest'))]" + } + } +} \ No newline at end of file diff --git a/Deployment/deploy.ps1 b/Deployment/deploy.ps1 index 0ef2ec427..09c1dd668 100644 --- a/Deployment/deploy.ps1 +++ b/Deployment/deploy.ps1 @@ -268,13 +268,25 @@ function GetAzureADApp { return $app } +# To get the Azure AD app detail with new secret. +function GetAzureADAppWithSecret { + param ($appName) + $app = GetAzureADApp $appName + + #Reset the app credentials to get the secret. The default validity of this secret will be for 1 year from the date its created. + WriteI -message "Retreiving new app with secrets..." + $appSecret = az ad app credential reset --id $app.appId --append | ConvertFrom-Json; + + return $appSecret +} + # Create/re-set Azure AD app. function CreateAzureADApp { param( [Parameter(Mandatory = $true)] [string] $AppName, + [Parameter(Mandatory = $false)] [bool] $ResetAppSecret = $true, [Parameter(Mandatory = $false)] [bool] $MultiTenant = $true, - [Parameter(Mandatory = $false)] [bool] $AllowImplicitFlow, - [Parameter(Mandatory = $false)] [bool] $ResetAppSecret = $true + [Parameter(Mandatory = $false)] [bool] $AllowImplicitFlow ) try { @@ -343,7 +355,13 @@ function CollectARMDeploymentLogs { $logsFolder = New-Item -ItemType Directory -Force -Path $logsPath + if($parameters.useCertificate.value) + { + az deployment operation group list --resource-group $parameters.resourceGroupName.Value --subscription $parameters.subscriptionId.Value --name azuredeploywithcert --query "[?properties.provisioningState=='Failed'].properties.statusMessage.error" | Set-Content $deploymentLogPath + } + else{ az deployment operation group list --resource-group $parameters.resourceGroupName.Value --subscription $parameters.subscriptionId.Value --name azuredeploy --query "[?properties.provisioningState=='Failed'].properties.statusMessage.error" | Set-Content $deploymentLogPath + } $activityLog = $null $retryCount = 5 @@ -387,7 +405,13 @@ function CollectARMDeploymentLogs { } function IsSourceControlTimeOut { + $failedResourcesList = $null + if($parameters.useCertificate.Value){ + $failedResourcesList = az deployment operation group list --resource-group $parameters.resourceGroupName.Value --subscription $parameters.subscriptionId.Value --name azuredeploywithcert --query "[?properties.provisioningState=='Failed']" | ConvertFrom-Json + } + else{ $failedResourcesList = az deployment operation group list --resource-group $parameters.resourceGroupName.Value --subscription $parameters.subscriptionId.Value --name azuredeploy --query "[?properties.provisioningState=='Failed']" | ConvertFrom-Json + } $nonCodeSyncErrors = $failedResourcesList | Where-Object {($null -ne $_.properties.targetResource -and 'Microsoft.Web/sites/sourcecontrols' -ne $_.properties.targetResource.resourceType)} return (0 -ne $failedResourcesList.length -and 0 -eq $nonCodeSyncErrors.length) } @@ -427,10 +451,12 @@ function WaitForCodeDeploymentSync { function DeployARMTemplate { Param( + [Parameter(Mandatory = $true)] $graphappid, [Parameter(Mandatory = $true)] $authorappId, - [Parameter(Mandatory = $true)] $authorsecret, [Parameter(Mandatory = $true)] $userappId, - [Parameter(Mandatory = $true)] $usersecret + [Parameter(Mandatory = $false)] $graphappsecret, + [Parameter(Mandatory = $false)] $authorsecret, + [Parameter(Mandatory = $false)] $usersecret ) try { if ((az group exists --name $parameters.resourceGroupName.Value --subscription $parameters.subscriptionId.Value) -eq $false) { @@ -469,7 +495,12 @@ function DeployARMTemplate { # Deploy ARM templates WriteI -message "`nDeploying app services, Azure function, bot service, and other supporting resources... (this step can take over an hour)" - $armDeploymentResult = az deployment group create --resource-group $parameters.resourceGroupName.Value --subscription $parameters.subscriptionId.Value --template-file 'azuredeploy.json' --parameters "baseResourceName=$($parameters.baseResourceName.Value)" "authorClientId=$authorappId" "authorClientSecret=$authorsecret" "userClientId=$userappId" "userClientSecret=$usersecret" "senderUPNList=$($parameters.senderUPNList.Value)" "customDomainOption=$($parameters.customDomainOption.Value)" "appDisplayName=$($parameters.appDisplayName.Value)" "appDescription=$($parameters.appDescription.Value)" "appIconUrl=$($parameters.appIconUrl.Value)" "tenantId=$($parameters.tenantId.Value)" "hostingPlanSku=$($parameters.hostingPlanSku.Value)" "hostingPlanSize=$($parameters.hostingPlanSize.Value)" "location=$($parameters.region.Value)" "gitRepoUrl=$($parameters.gitRepoUrl.Value)" "gitBranch=$($parameters.gitBranch.Value)" "ProactivelyInstallUserApp=$($parameters.proactivelyInstallUserApp.Value)" "UserAppExternalId=$($parameters.userAppExternalId.Value)" "DefaultCulture=$($parameters.defaultCulture.Value)" "SupportedCultures=$($parameters.supportedCultures.Value)" + if($parameters.useCertificate.Value){ + $armDeploymentResult = az deployment group create --resource-group $parameters.resourceGroupName.Value --subscription $parameters.subscriptionId.Value --template-file 'azuredeploywithcert.json' --parameters "baseResourceName=$($parameters.baseResourceName.Value)" "authorClientId=$authorappId" "authorAppCertName=$($parameters.authorAppCertName.Value)" "graphAppId=$graphappid" "graphAppCertName=$($parameters.graphAppCertName.Value)" "userClientId=$userappId" "userAppCertName=$($parameters.userAppCertName.Value)" "senderUPNList=$($parameters.senderUPNList.Value)" "customDomainOption=$($parameters.customDomainOption.Value)" "appDisplayName=$($parameters.appDisplayName.Value)" "appDescription=$($parameters.appDescription.Value)" "appIconUrl=$($parameters.appIconUrl.Value)" "tenantId=$($parameters.tenantId.Value)" "hostingPlanSku=$($parameters.hostingPlanSku.Value)" "hostingPlanSize=$($parameters.hostingPlanSize.Value)" "location=$($parameters.region.Value)" "gitRepoUrl=$($parameters.gitRepoUrl.Value)" "gitBranch=$($parameters.gitBranch.Value)" "ProactivelyInstallUserApp=$($parameters.proactivelyInstallUserApp.Value)" "objectId=$($parameters.UserObjectId.Value)" "UserAppExternalId=$($parameters.userAppExternalId.Value)" "DefaultCulture=$($parameters.defaultCulture.Value)" "SupportedCultures=$($parameters.supportedCultures.Value)" "serviceBusWebAppRoleNameGuid=$($parameters.serviceBusWebAppRoleNameGuid.Value)" "serviceBusPrepFuncRoleNameGuid=$($parameters.serviceBusPrepFuncRoleNameGuid.Value)" "serviceBusSendFuncRoleNameGuid=$($parameters.serviceBusSendFuncRoleNameGuid.Value)" "serviceBusDataFuncRoleNameGuid=$($parameters.serviceBusDataFuncRoleNameGuid.Value)" "storageAccountWebAppRoleNameGuid=$($parameters.storageAccountWebAppRoleNameGuid.Value)" "storageAccountPrepFuncRoleNameGuid=$($parameters.storageAccountPrepFuncRoleNameGuid.Value)" "storageAccountDataFuncRoleNameGuid=$($parameters.storageAccountDataFuncRoleNameGuid.Value)" + } + else{ + $armDeploymentResult = az deployment group create --resource-group $parameters.resourceGroupName.Value --subscription $parameters.subscriptionId.Value --template-file 'azuredeploy.json' --parameters "baseResourceName=$($parameters.baseResourceName.Value)" "authorClientId=$authorappId" "authorClientSecret=$authorsecret" "graphAppId=$graphappid" "graphAppSecret=$graphappsecret" "userClientId=$userappId" "userClientSecret=$usersecret" "senderUPNList=$($parameters.senderUPNList.Value)" "customDomainOption=$($parameters.customDomainOption.Value)" "appDisplayName=$($parameters.appDisplayName.Value)" "appDescription=$($parameters.appDescription.Value)" "appIconUrl=$($parameters.appIconUrl.Value)" "tenantId=$($parameters.tenantId.Value)" "hostingPlanSku=$($parameters.hostingPlanSku.Value)" "hostingPlanSize=$($parameters.hostingPlanSize.Value)" "location=$($parameters.region.Value)" "gitRepoUrl=$($parameters.gitRepoUrl.Value)" "gitBranch=$($parameters.gitBranch.Value)" "ProactivelyInstallUserApp=$($parameters.proactivelyInstallUserApp.Value)" "UserAppExternalId=$($parameters.userAppExternalId.Value)" "DefaultCulture=$($parameters.defaultCulture.Value)" "SupportedCultures=$($parameters.supportedCultures.Value)" "serviceBusWebAppRoleNameGuid=$($parameters.serviceBusWebAppRoleNameGuid.Value)" "serviceBusPrepFuncRoleNameGuid=$($parameters.serviceBusPrepFuncRoleNameGuid.Value)" "serviceBusSendFuncRoleNameGuid=$($parameters.serviceBusSendFuncRoleNameGuid.Value)" "serviceBusDataFuncRoleNameGuid=$($parameters.serviceBusDataFuncRoleNameGuid.Value)" "storageAccountWebAppRoleNameGuid=$($parameters.storageAccountWebAppRoleNameGuid.Value)" "storageAccountPrepFuncRoleNameGuid=$($parameters.storageAccountPrepFuncRoleNameGuid.Value)" "storageAccountDataFuncRoleNameGuid=$($parameters.storageAccountDataFuncRoleNameGuid.Value)" + } $deploymentExceptionMessage = "ERROR: ARM template deployment error." if ($LASTEXITCODE -ne 0) { @@ -484,7 +515,12 @@ function DeployARMTemplate { if($appserviceCodeSyncSuccess){ WriteI -message "Re-running deployment to fetch output..." - $armDeploymentResult = az deployment group create --resource-group $parameters.resourceGroupName.Value --subscription $parameters.subscriptionId.Value --template-file 'azuredeploy.json' --parameters "baseResourceName=$($parameters.baseResourceName.Value)" "authorClientId=$authorappId" "authorClientSecret=$authorsecret" "userClientId=$userappId" "userClientSecret=$usersecret" "senderUPNList=$($parameters.senderUPNList.Value)" "customDomainOption=$($parameters.customDomainOption.Value)" "appDisplayName=$($parameters.appDisplayName.Value)" "appDescription=$($parameters.appDescription.Value)" "appIconUrl=$($parameters.appIconUrl.Value)" "tenantId=$($parameters.tenantId.Value)" "hostingPlanSku=$($parameters.hostingPlanSku.Value)" "hostingPlanSize=$($parameters.hostingPlanSize.Value)" "location=$($parameters.region.Value)" "gitRepoUrl=$($parameters.gitRepoUrl.Value)" "gitBranch=$($parameters.gitBranch.Value)" "ProactivelyInstallUserApp=$($parameters.proactivelyInstallUserApp.Value)" "UserAppExternalId=$($parameters.userAppExternalId.Value)" "DefaultCulture=$($parameters.defaultCulture.Value)" "SupportedCultures=$($parameters.supportedCultures.Value)" + if($parameters.useCertificate.Value){ + $armDeploymentResult = az deployment group create --resource-group $parameters.resourceGroupName.Value --subscription $parameters.subscriptionId.Value --template-file 'azuredeploywithcert.json' --parameters "baseResourceName=$($parameters.baseResourceName.Value)" "authorClientId=$authorappId" "authorAppCertName=$($parameters.authorAppCertName.Value)" "graphAppId=$graphappid" "graphAppCertName=$($parameters.graphAppCertName.Value)" "userClientId=$userappId" "userAppCertName=$($parameters.userAppCertName.Value)" "senderUPNList=$($parameters.senderUPNList.Value)" "customDomainOption=$($parameters.customDomainOption.Value)" "appDisplayName=$($parameters.appDisplayName.Value)" "appDescription=$($parameters.appDescription.Value)" "appIconUrl=$($parameters.appIconUrl.Value)" "tenantId=$($parameters.tenantId.Value)" "hostingPlanSku=$($parameters.hostingPlanSku.Value)" "hostingPlanSize=$($parameters.hostingPlanSize.Value)" "location=$($parameters.region.Value)" "gitRepoUrl=$($parameters.gitRepoUrl.Value)" "gitBranch=$($parameters.gitBranch.Value)" "ProactivelyInstallUserApp=$($parameters.proactivelyInstallUserApp.Value)" "objectId=$($parameters.UserObjectId.Value)" "UserAppExternalId=$($parameters.userAppExternalId.Value)" "DefaultCulture=$($parameters.defaultCulture.Value)" "SupportedCultures=$($parameters.supportedCultures.Value)" "serviceBusWebAppRoleNameGuid=$($parameters.serviceBusWebAppRoleNameGuid.Value)" "serviceBusPrepFuncRoleNameGuid=$($parameters.serviceBusPrepFuncRoleNameGuid.Value)" "serviceBusSendFuncRoleNameGuid=$($parameters.serviceBusSendFuncRoleNameGuid.Value)" "serviceBusDataFuncRoleNameGuid=$($parameters.serviceBusDataFuncRoleNameGuid.Value)" "storageAccountWebAppRoleNameGuid=$($parameters.storageAccountWebAppRoleNameGuid.Value)" "storageAccountPrepFuncRoleNameGuid=$($parameters.storageAccountPrepFuncRoleNameGuid.Value)" "storageAccountDataFuncRoleNameGuid=$($parameters.storageAccountDataFuncRoleNameGuid.Value)" + } + else{ + $armDeploymentResult = az deployment group create --resource-group $parameters.resourceGroupName.Value --subscription $parameters.subscriptionId.Value --template-file 'azuredeploy.json' --parameters "baseResourceName=$($parameters.baseResourceName.Value)" "authorClientId=$authorappId" "authorClientSecret=$authorsecret" "graphAppId=$graphappid" "graphAppSecret=$graphappsecret" "userClientId=$userappId" "userClientSecret=$usersecret" "senderUPNList=$($parameters.senderUPNList.Value)" "customDomainOption=$($parameters.customDomainOption.Value)" "appDisplayName=$($parameters.appDisplayName.Value)" "appDescription=$($parameters.appDescription.Value)" "appIconUrl=$($parameters.appIconUrl.Value)" "tenantId=$($parameters.tenantId.Value)" "hostingPlanSku=$($parameters.hostingPlanSku.Value)" "hostingPlanSize=$($parameters.hostingPlanSize.Value)" "location=$($parameters.region.Value)" "gitRepoUrl=$($parameters.gitRepoUrl.Value)" "gitBranch=$($parameters.gitBranch.Value)" "ProactivelyInstallUserApp=$($parameters.proactivelyInstallUserApp.Value)" "UserAppExternalId=$($parameters.userAppExternalId.Value)" "DefaultCulture=$($parameters.defaultCulture.Value)" "SupportedCultures=$($parameters.supportedCultures.Value)" "serviceBusWebAppRoleNameGuid=$($parameters.serviceBusWebAppRoleNameGuid.Value)" "serviceBusPrepFuncRoleNameGuid=$($parameters.serviceBusPrepFuncRoleNameGuid.Value)" "serviceBusSendFuncRoleNameGuid=$($parameters.serviceBusSendFuncRoleNameGuid.Value)" "serviceBusDataFuncRoleNameGuid=$($parameters.serviceBusDataFuncRoleNameGuid.Value)" "storageAccountWebAppRoleNameGuid=$($parameters.storageAccountWebAppRoleNameGuid.Value)" "storageAccountPrepFuncRoleNameGuid=$($parameters.storageAccountPrepFuncRoleNameGuid.Value)" "storageAccountDataFuncRoleNameGuid=$($parameters.storageAccountDataFuncRoleNameGuid.Value)" + } } else{ CollectARMDeploymentLogs Throw $deploymentExceptionMessage @@ -506,10 +542,18 @@ function DeployARMTemplate { } } WriteS -message "Finished deploying resources. ARM template deployment succeeded." - - #get the output of current deployment - $deploymentOutput = az deployment group show --name azuredeploy --resource-group $parameters.resourceGroupName.Value --subscription $parameters.subscriptionId.Value | ConvertFrom-Json + #get the output of current deployment + $deploymentOutput = $null + if($parameters.useCertificate.value) + { + $deploymentOutput = az deployment group show --name azuredeploywithcert --resource-group $parameters.resourceGroupName.Value --subscription $parameters.subscriptionId.Value | ConvertFrom-Json + } + else + { + $deploymentOutput = az deployment group show --name azuredeploy --resource-group $parameters.resourceGroupName.Value --subscription $parameters.subscriptionId.Value | ConvertFrom-Json + } + # Sync only in upgrades & if no source branch conflict detected if($parameters.isUpgrade.Value -and (-not $codeSynced)){ # sync app services code deployment (ARM deployment will not sync automatically) @@ -533,39 +577,73 @@ function DeployARMTemplate { } } -# Create Azure AD App principal if app is used in other tenants -function CreateAdAppPrincipal { +function CreateCertificateInKeyVault { Param( - [Parameter(Mandatory = $true)] $tenantId, - [Parameter(Mandatory = $true)] $authorAppId, - [Parameter(Mandatory = $true)] $userAppId + [Parameter(Mandatory= $true)] $certificateName, + [Parameter(Mandatory= $true)] $keyVaultName, + [Parameter(Mandatory= $true)] $domainName ) - WriteI -message "`nPlease login to the tenant where this app template will be used in Microsoft Teams." - $user = az login --tenant $tenantId --allow-no-subscriptions - - $sp = az ad sp list --filter "appId eq '$authorAppId'" - if (0 -eq ($sp | ConvertFrom-Json).length) { - WriteI -message "Azure AD app principal will be created in tenant: $tenantId" - - # Delete old service principal for user app - $sp = az ad sp list --filter "appId eq '$userAppId'" - if (0 -ne ($sp | ConvertFrom-Json).length) { - $sp = az ad sp delete --id $userAppId - } - - # create new service principal - $sp = az ad sp create --id $authorAppId + #Get existing Azure Key Vault information + $azKeyVault = Get-AzKeyVault -Name $keyVaultName -ErrorAction SilentlyContinue + if ($null -eq $azKeyVault) + { + Write-Host "Didn't find Key Vault with name Azure:- $keyVaultName" -BackgroundColor DarkRed + break } - - $logOut = az logout - WriteW -message "`nPlease inform your admin to consent the app permissions from this link`nhttps://login.microsoftonline.com/$tenantId/adminconsent?client_id=$authorAppId" -} + else + { + Write-Host "Found Key Vault Name:- $keyVaultName" -BackgroundColor DarkGreen + } + #Generate new Azure Key Vault Certificate + Write-Host "Processing creation of Azure Key Vault Certificate" -ForegroundColor Yellow + $certSubjectName = 'cn=' + $domainName + $azKeyVaultCertPolicy = New-AzKeyVaultCertificatePolicy -SecretContentType "application/x-pkcs12" -SubjectName $certSubjectName -IssuerName "Self" -ValidityInMonths 24 -ReuseKeyOnRenewal + $azKeyVaultCertStatus = Add-AzKeyVaultCertificate -VaultName $keyVaultName -Name $CertificateName -CertificatePolicy $azKeyVaultCertPolicy + + #Wait for certificate to generate + $counter = 1 + While ($azKeyVaultCertStatus.Status -eq 'inProgress') { + Start-Sleep -Milliseconds 50 + Write-Host "`r$counter% creation in progress" -NoNewline -ForegroundColor Yellow + $azKeyVaultCertStatus = Get-AzKeyVaultCertificateOperation -VaultName $keyVaultName -Name $CertificateName + $counter++ + } + Write-Host "`r100% Completed. Checking status... " -ForegroundColor Yellow + if ($azKeyVaultCertStatus.Status -ne 'completed') { + Write-Host $($azKeyVaultCertStatus.StatusDetails) -ForegroundColor Magenta + } + else { + Write-Host "Generated Key Vault Certificate successfully" -BackgroundColor DarkGreen + Write-Output $azKeyVaultCertStatus + } +} + +function UpdateAadAppWithCertificate { + Param( + [Parameter(Mandatory = $true)] $appId, + [Parameter(Mandatory = $true)] $keyVaultName, + [Parameter(Mandatory = $true)] $certificateName + ) + # Update AAD app with keyvault certificate + az ad app credential reset --id $appId --keyvault $keyVaultName --cert $certificateName --append +} + +function ImportKeyVaultCertificate{ + Param( + [Parameter(Mandatory = $true)] $keyVaultName, + [Parameter(Mandatory = $true)] $appName + ) + Set-AzKeyVaultAccessPolicy -VaultName $keyVaultName -ServicePrincipalName abfa0a7c-a6b6-4736-8310-5855508787cd -PermissionsToSecrets get + az webapp config ssl import --resource-group $parameters.resourceGroupName.Value --name $appName --subscription $parameters.subscriptionId.Value --key-vault $keyVaultName --key-vault-certificate-name $parameters.authorAppCertName.Value + az webapp config ssl import --resource-group $parameters.resourceGroupName.Value --name $appName --subscription $parameters.subscriptionId.Value --key-vault $keyVaultName --key-vault-certificate-name $parameters.userAppCertName.Value + az webapp config ssl import --resource-group $parameters.resourceGroupName.Value --name $appName --subscription $parameters.subscriptionId.Value --key-vault $keyVaultName --key-vault-certificate-name $parameters.graphAppCertName.Value +} # Grant Admin consent function GrantAdminConsent { Param( - [Parameter(Mandatory = $true)] $authorAppId + [Parameter(Mandatory = $true)] $graphAppId ) $confirmationTitle = "Admin consent permissions is required for app registration using CLI" @@ -573,8 +651,8 @@ function GrantAdminConsent { $confirmationChoices = "&Yes", "&No" # 0 = Yes, 1 = No $consentErrorMessage = "Current user does not have the privilege to consent the below permissions on this app. * AppCatalog.Read.All(Delegated) - * Group.Read.All(Delegated) - * Group.Read.All(Application) + * GroupMember.Read.All(Delegated) + * GroupMember.Read.All(Application) * TeamsAppInstallation.ReadWriteForUser.All(Application) * User.Read.All(Delegated) * User.Read(Application) @@ -584,16 +662,16 @@ function GrantAdminConsent { if ($updateDecision -eq 0) { # Grant admin consent for app registration required permissions using CLI WriteI -message "Waiting for admin consent to finish..." - az ad app permission admin-consent --id $authorAppId + az ad app permission admin-consent --id $graphAppId if ($LASTEXITCODE -ne 0) { WriteE -message $consentErrorMessage - WriteW -message "`nPlease inform the global admin to consent the app permissions from this link`nhttps://login.microsoftonline.com/$($parameters.tenantId.value)/adminconsent?client_id=$authorAppId" + WriteW -message "`nPlease inform the global admin to consent the app permissions from this link`nhttps://login.microsoftonline.com/$($parameters.tenantId.value)/adminconsent?client_id=$graphAppId" } else { WriteS -message "Admin consent has been granted." } } else { - WriteW -message "`nPlease inform the global admin to consent the app permissions from this link`nhttps://login.microsoftonline.com/$($parameters.tenantId.value)/adminconsent?client_id=$authorAppId" + WriteW -message "`nPlease inform the global admin to consent the app permissions from this link`nhttps://login.microsoftonline.com/$($parameters.tenantId.value)/adminconsent?client_id=$graphAppId" } } @@ -608,7 +686,7 @@ function ADAppUpdate { $configAppUrl = "https://$azureDomainBase" $RedirectUris = ($configAppUrl + '/signin-simple-end') $IdentifierUris = "api://$azureDomainBase" - $appName = $parameters.baseResourceName.Value + '-authors' + $appName = $parameters.baseResourceName.Value function CreatePreAuthorizedApplication( [string] $applicationIdToPreAuthorize, @@ -637,11 +715,12 @@ function ADAppUpdate { return $scope } - # Grant Admin consent if the subscriptionTenantId and tenantId are same. - if ($parameters.tenantId.value -eq $parameters.subscriptionTenantId.value) { - GrantAdminConsent $configAppId - } + # Grant Admin consent + GrantAdminConsent $configAppId + # set subscription + az account set --subscription $parameters.subscriptionId.Value + # Assigning graph permissions az ad app update --id $configAppId --required-resource-accesses './AadAppManifest.json' @@ -661,10 +740,10 @@ function ADAppUpdate { # Do nothing if the app has already been configured if ($app.IdentifierUris.Count -gt 0) { - WriteS -message "`Author application is already configured." + WriteS -message "`Graph application is already configured." return } - WriteI -message "`nUpdating authors app..." + WriteI -message "`nUpdating graph app..." #Removing default scope user_impersonation $DEFAULT_SCOPE=$(az ad app show --id $configAppId | jq '.oauth2Permissions[0].isEnabled = false' | jq -r '.oauth2Permissions') @@ -728,13 +807,35 @@ function ADAppUpdate { WriteI -message "Teams mobile/desktop and web clients applications pre-authorized." } -# Removing existing access of user app. -function ADAppUpdateUser { - Param( - [Parameter(Mandatory = $true)] $appId +# update app name +function ADAppUpdateDisplayName{ + Param( + [Parameter(Mandatory = $true)] $appId, + [Parameter(Mandatory = $true)] $currentName, + [Parameter(Mandatory = $true)] $newName ) - $appName = $parameters.baseResourceName.Value + $apps = Get-AzureADApplication -Filter "DisplayName eq '$currentName'" + + if (0 -eq $apps.Length) { + $app = New-AzureADApplication -DisplayName $currentName + } else { + $app = $apps[0] + } + + $applicationObjectId = $app.ObjectId + + $app = Get-AzureADMSApplication -ObjectId $applicationObjectId + + az ad app update --id $appId --set DisplayName=$newName +} + +# Removing existing access of app. +function FormatAADApp { + Param( + [Parameter(Mandatory = $true)] $appId, + [Parameter(Mandatory = $true)] $appName + ) $apps = Get-AzureADApplication -Filter "DisplayName eq '$appName'" @@ -750,11 +851,11 @@ function ADAppUpdateUser { # Do nothing if the app has already been configured if ($app.IdentifierUris.Count -eq 0) { - WriteS -message "`nUser app already configured." + WriteS -message "`n app already configured." return } - WriteI -message "`nUpdating user app..." + WriteI -message "`nUpdating app..." $IdentifierUris = "api://$appId" $DEFAULT_SCOPE=$(az ad app show --id $appId | jq '.oauth2Permissions[0].isEnabled = false' | jq -r '.oauth2Permissions') @@ -921,7 +1022,7 @@ function logout { } # Start Deployment. - Write-Ascii -InputObject "Company Communicator v4" -ForegroundColor Magenta + Write-Ascii -InputObject "Company Communicator v5.0" -ForegroundColor Magenta WriteI -message "Starting deployment..." # Initialize connections - Azure Az/CLI/Azure AD @@ -944,51 +1045,130 @@ function logout { logout EXIT } - -# Create User App - $userAppCred = CreateAzureADApp $parameters.baseresourcename.Value - if ($null -eq $userAppCred) { - WriteE -message "Failed to create or update User app in Azure Active Directory. Exiting..." - logout - Exit - } - + +# Create or Update User App + $usersApp = $parameters.baseresourcename.Value + '-users' + $userAppCred = $null + + if($parameters.isUpgrade.Value){ + $currentAppName = $parameters.baseresourcename.Value + $userAppCred = GetAzureADAppWithSecret $currentAppName + ADAppUpdateDisplayName $userAppCred.appId $currentAppName $usersApp + } + else + { + $userAppCred = CreateAzureADApp $usersApp + if ($null -eq $userAppCred) { + WriteE -message "Failed to create or update User app in Azure Active Directory. Exiting..." + logout + Exit + } + } + # Create Author App $authorsApp = $parameters.baseResourceName.Value + '-authors' - $authorAppCred = CreateAzureADApp $authorsApp - if ($null -eq $authorAppCred) { + $authorAppCred = $null + if($parameters.isUpgrade.Value){ + $authorAppCred = GetAzureADAppWithSecret $authorsApp + } + else + { + $authorAppCred = CreateAzureADApp $authorsApp + if ($null -eq $authorAppCred) { WriteE -message "Failed to create or update the Author app in Azure Active Directory. Exiting..." logout Exit - } + } + } + +# Create Company Communicator App + $graphApp = $parameters.baseResourceName.Value + $graphAppCred = CreateAzureADApp -AppName $graphApp -ResetAppSecret $True -MultiTenant $False + if ($null -eq $graphAppCred) { + WriteE -message "Failed to create or update the main app in Azure Active Directory. Exiting..." + logout + Exit + } # Function call to Deploy ARM Template - $deploymentOutput = DeployARMTemplate $authorAppCred.appId $authorAppCred.password $userAppCred.appId $userAppCred.password + $deploymentOutput = $null + $appDisplayName = $null + if($parameters.useCertificate.Value){ + $deploymentOutput = DeployARMTemplate $graphAppCred.appId $authorAppCred.appId $userAppCred.appId + + # Reading the deployment output. + WriteI -message "Reading deployment outputs..." + if(($null -eq $deploymentOutput) -or ( $null -eq $deploymentOutput.properties) -or ($null -eq $deploymentOutput.properties.Outputs) -or ($deploymentOutput.properties.Outputs.keyVaultName) -or ($deploymentOutput.properties.Outputs.keyVaultName.Value)) + { + $keyVaultName = $parameters.BaseResourceName.Value + 'vault' + if($parameters.customDomainOption.Value -eq 'Azure Front Door') + { + $appdomainName = $parameters.BaseResourceName.Value.ToLower() + '.azurefd.net' + } + else + { + $appdomainName = 'Please create a custom domain name for ' + $parameters.BaseResourceName.Value + ' and use that in the manifest' + } + } + else + { + $keyVaultName = $deploymentOutput.properties.Outputs.keyVaultName.Value + $appdomainName = $deploymentOutput.properties.Outputs.appDomain.Value + } + + CreateCertificateInKeyVault $parameters.authorAppCertName.value $keyVaultName $appdomainName + CreateCertificateInKeyVault $parameters.userAppCertName.value $keyVaultName $appdomainName + CreateCertificateInKeyVault $parameters.graphAppCertName.value $keyVaultName $appdomainName + + ImportKeyVaultCertificate $keyVaultName $parameters.BaseResourceName.Value + ImportKeyVaultCertificate $keyVaultName "$($parameters.BaseResourceName.Value)-prep-function" + ImportKeyVaultCertificate $keyVaultName "$($parameters.BaseResourceName.Value)-function" + ImportKeyVaultCertificate $keyVaultName "$($parameters.BaseResourceName.Value)-data-function" + + UpdateAadAppWithCertificate $authorAppCred.appId $keyVaultName $parameters.authorAppCertName.value + UpdateAadAppWithCertificate $userAppCred.appId $keyVaultName $parameters.userAppCertName.value + UpdateAadAppWithCertificate $graphAppCred.appId $keyVaultName $parameters.graphAppCertName.value + } + else + { + $deploymentOutput = DeployARMTemplate $graphAppCred.appId $authorAppCred.appId $userAppCred.appId $graphAppCred.password $authorAppCred.password $userAppCred.password + + # Reading the deployment output. + WriteI -message "Reading deployment outputs..." + if(($null -eq $deploymentOutput) -or ( $null -eq $deploymentOutput.properties) -or ($null -eq $deploymentOutput.properties.Outputs) -or ($deploymentOutput.properties.Outputs.keyVaultName) -or ($deploymentOutput.properties.Outputs.keyVaultName.Value)) + { + $keyVaultName = $parameters.BaseResourceName.Value + 'vault' + if($parameters.customDomainOption.Value -eq 'Azure Front Door') + { + $appdomainName = $parameters.BaseResourceName.Value.ToLower() + '.azurefd.net' + } + else + { + $appdomainName = 'Please create a custom domain name for ' + $parameters.BaseResourceName.Value + ' and use that in the manifest' + } + } + else + { + # Assigning return values to variable. + $appdomainName = $deploymentOutput.properties.Outputs.appDomain.Value + } + } if ($null -eq $deploymentOutput) { WriteE -message "Encountered an error during ARM template deployment. Exiting..." logout Exit - } - -# Reading the deployment output. - WriteI -message "Reading deployment outputs..." - -# Assigning return values to variable. - $appdomainName = $deploymentOutput.properties.Outputs.appDomain.Value + } # Function call to update reply-urls and uris for registered app. WriteI -message "Updating required parameters and urls..." - ADAppUpdateUser $userAppCred.appId - ADAppUpdate $appdomainName $authorAppCred.appId + if($parameters.isUpgrade.Value){ + FormatAADApp $authorAppCred.appId $authorsApp + } + ADAppUpdate $appdomainName $graphAppCred.appId # Log out to avoid tokens caching logout -# App template is deployed on tenant A and used in tenant B - if ($parameters.tenantId.Value -ne $parameters.subscriptionTenantId.Value){ - CreateAdAppPrincipal $parameters.tenantId.Value $authorAppCred.appId $userAppCred.appId - } - # Function call to generate manifest.zip folder for User and Author. GenerateAppManifestPackage 'authors' $appdomainName $authorAppCred.appId GenerateAppManifestPackage 'users' $appdomainName $userAppCred.appId diff --git a/Deployment/parameters.json b/Deployment/parameters.json index b43fe58f3..7b2f73eca 100644 --- a/Deployment/parameters.json +++ b/Deployment/parameters.json @@ -7,6 +7,10 @@ "Value": "<>", "Description": "Id of the tenant to deploy to (If you are not sure how to get Tenant ID, please check Azure Active Directory in Azure Portal. Under Manage, click Properties. The tenant ID is shown in the Directory ID box). e.g 98f3ece2-3a5a-428b-aa4f-4c41b3f6eef0. Tenant ID is also in the \"Overview\" section\"" }, + "UserObjectId": { + "Value": "<>", + "Description": "User Object Id." + }, "resourceGroupName": { "Value": "<>", "Description": "Resource Group" @@ -27,8 +31,24 @@ "Value": "<>", "Description": "Semicolon-delimited list of the user principal names (UPNs) allowed to send messages." }, + "useCertificate": { + "Value": false, + "Description": "If certificate authentication is being used, then value should be true. Otherwise, false is default (Client-secret will be used)." + }, + "authorAppCertName": { + "Value": "<>", + "Description": "The X.509 certificate name of the author bot Azure AD app." + }, + "graphAppCertName": { + "Value": "<>", + "Description": "The X.509 certificate name of the Microsoft Azure AD app." + }, + "userAppCertName": { + "Value": "<>", + "Description": "The X.509 certificate name of the user bot Azure AD app." + }, "isUpgrade": { - "Value": "false", + "Value": false, "Description": "If this is an upgrade for old version of the app template, then value should be true. Otherwise, false is default (First-time deployment)." }, "customDomainOption": { @@ -43,6 +63,34 @@ "Value": "148a66bb-e83d-425a-927d-09f4299a9274", "Description": "User app external ID." }, + "serviceBusWebAppRoleNameGuid": { + "Value": "958380b3-630d-4823-b933-f59d92cdcada", + "Description": "A GUID used to identify the role assignment. This is Default value." + }, + "serviceBusPrepFuncRoleNameGuid": { + "Value": "ce6ca916-08e9-4639-bfbe-9d098baf42ca", + "Description": "A GUID used to identify the role assignment. This is Default value." + }, + "serviceBusSendFuncRoleNameGuid": { + "Value": "960365a2-c7bf-4ff3-8887-efa86fe4a163", + "Description": "A GUID used to identify the role assignment. This is Default value." + }, + "serviceBusDataFuncRoleNameGuid": { + "Value": "d42703bc-421d-4d98-bc4d-cd2bb16e5b0a", + "Description": "A GUID used to identify the role assignment. This is Default value." + }, + "storageAccountWebAppRoleNameGuid": { + "Value": "edd0cc48-2cf7-490e-99e8-131311e42030", + "Description": "A GUID used to identify the role assignment. This is Default value." + }, + "storageAccountPrepFuncRoleNameGuid": { + "Value": "9332a9e9-93f4-48d9-8121-d279f30a732e", + "Description": "A GUID used to identify the role assignment. This is Default value." + }, + "storageAccountDataFuncRoleNameGuid": { + "Value": "5b67af51-4a98-47e1-9d22-745069f51a13", + "Description": "A GUID used to identify the role assignment. This is Default value." + }, "defaultCulture": { "Value": "en-US", "Description": "Default culture." @@ -53,10 +101,10 @@ }, "hostingPlanSku": { "Value": "Standard", - "Description": "The pricing tier for the hosting plan. Defaul value: Standard. You may choose between Basic, Standard and Premium." + "Description": "The pricing tier for the hosting plan. Default value: Standard. You may choose between Basic, Standard and Premium." }, "hostingPlanSize": { - "Value": "1", + "Value": "2", "Description": "The size of the hosting plan (small - 1, medium - 2, or large - 3). Default value: 1" }, "gitRepoUrl": { diff --git a/Manifest/manifest_authors.json b/Manifest/manifest_authors.json index f069ae919..9af81d8a7 100644 --- a/Manifest/manifest_authors.json +++ b/Manifest/manifest_authors.json @@ -1,7 +1,7 @@ { "$schema": "https://developer.microsoft.com/en-us/json-schemas/teams/v1.5/MicrosoftTeams.schema.json", "manifestVersion": "1.5", - "version": "4.1.5", + "version": "5.0.0", "id": "1c07cd26-a088-4db8-8928-ace382fa219f", "packageName": "com.microsoft.teams.companycommunicator.authors", "developer": { diff --git a/Manifest/manifest_users.json b/Manifest/manifest_users.json index be5985a3c..f75126404 100644 --- a/Manifest/manifest_users.json +++ b/Manifest/manifest_users.json @@ -1,7 +1,7 @@ { "$schema": "https://developer.microsoft.com/en-us/json-schemas/teams/v1.5/MicrosoftTeams.schema.json", "manifestVersion": "1.5", - "version": "4.1.5", + "version": "5.0.0", "id": "148a66bb-e83d-425a-927d-09f4299a9274", "packageName": "com.microsoft.teams.companycommunicator", "developer": { diff --git a/README.md b/README.md index 57a193849..71f868acd 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # Company Communicator App Template -| [Documentation](https://github.com/OfficeDev/microsoft-teams-company-communicator-app/wiki) | [Deployment guide](https://github.com/OfficeDev/microsoft-teams-company-communicator-app/wiki/Deployment-guide) | [Deployment guide powershell](https://github.com/OfficeDev/microsoft-teams-company-communicator-app/wiki/Deployment-guide-powershell) | [Architecture](https://github.com/OfficeDev/microsoft-teams-company-communicator-app/wiki/Solution-overview) | -| ---- | ---- | ---- | ---- | +| [Documentation](https://github.com/OfficeDev/microsoft-teams-company-communicator-app/wiki) | [Deployment guide powershell](https://github.com/OfficeDev/microsoft-teams-company-communicator-app/wiki/Deployment-guide-powershell) |[Deployment guide](https://github.com/OfficeDev/microsoft-teams-company-communicator-app/wiki/Deployment-guide) | [Deployment guide certificate](https://github.com/OfficeDev/microsoft-teams-company-communicator-app/wiki/Deployment-guide-certificate) | [Architecture](https://github.com/OfficeDev/microsoft-teams-company-communicator-app/wiki/Solution-overview) | +| ---- | ---- | ---- | ---- | ---- | Company Communicator is a custom Teams app that enables corporate teams to create and send messages intended for multiple teams or large number of employees over chat allowing organization to reach employees right where they collaborate. Use this template for multiple scenarios, such as new initiative announcements, employee onboarding, modern learning and development, or organization-wide broadcasts. @@ -19,8 +19,12 @@ The app provides an easy interface for designated users to create, preview, coll Begin with the [Solution overview](https://github.com/OfficeDev/microsoft-teams-company-communicator-app/wiki/Solution-overview) to read about what the app does and how it works. When you're ready to try out Company Communicator, or to use it in your own organization, you can choose to follow one of the below guides. +* [Deployment guide powershell](https://github.com/OfficeDev/microsoft-teams-company-communicator-app/wiki/Deployment-guide-powershell). + * **Recommended** Use this option to deploy the Company Communicator using powershell script. The entire set-up is done by the powershell script. * [Deployment guide](https://github.com/OfficeDev/microsoft-teams-company-communicator-app/wiki/Deployment-guide). -* [Deployment guide powershell](https://github.com/OfficeDev/microsoft-teams-company-communicator-app/wiki/Deployment-guide-powershell). + * Use this option to deploy the Company Communicator with client secrets. +* [Deployment guide certificate](https://github.com/OfficeDev/microsoft-teams-company-communicator-app/wiki/Deployment-guide-certificate). + * Use this option to deploy the Company Communicator with certificates. ## Feedback diff --git a/Source/CompanyCommunicator.Common/Adapter/CCBotFrameworkHttpAdapter.cs b/Source/CompanyCommunicator.Common/Adapter/CCBotFrameworkHttpAdapter.cs index b1e89ba9d..dbd5a955c 100644 --- a/Source/CompanyCommunicator.Common/Adapter/CCBotFrameworkHttpAdapter.cs +++ b/Source/CompanyCommunicator.Common/Adapter/CCBotFrameworkHttpAdapter.cs @@ -5,34 +5,76 @@ namespace Microsoft.Teams.Apps.CompanyCommunicator.Common.Adapter { + using System; using System.Threading; using System.Threading.Tasks; using Microsoft.Bot.Builder; using Microsoft.Bot.Builder.Integration.AspNet.Core; using Microsoft.Bot.Connector.Authentication; using Microsoft.Bot.Schema; + using Microsoft.Teams.Apps.CompanyCommunicator.Common.Secrets; /// /// Bot framework http adapter instance. /// public class CCBotFrameworkHttpAdapter : BotFrameworkHttpAdapter, ICCBotFrameworkHttpAdapter { - private readonly ICredentialProvider credentialProvider; + private readonly ICertificateProvider certificateProvider; /// /// Initializes a new instance of the class. /// /// credential provider. - public CCBotFrameworkHttpAdapter(ICredentialProvider credentialProvider) + /// certificate provider. + public CCBotFrameworkHttpAdapter( + ICredentialProvider credentialProvider, + ICertificateProvider certificateProvider) : base(credentialProvider) { - this.credentialProvider = credentialProvider; + this.certificateProvider = certificateProvider; } /// - public override Task CreateConversationAsync(string channelId, string serviceUrl, MicrosoftAppCredentials credentials, ConversationParameters conversationParameters, BotCallbackHandler callback, CancellationToken cancellationToken) + public async Task CreateConversationUsingCertificateAsync(string channelId, string serviceUrl, AppCredentials appCredentials, ConversationParameters conversationParameters, BotCallbackHandler callback, CancellationToken cancellationToken) { - return base.CreateConversationAsync(channelId, serviceUrl, credentials, conversationParameters, callback, cancellationToken); + var cert = await this.certificateProvider.GetCertificateAsync(appCredentials.MicrosoftAppId); + var options = new CertificateAppCredentialsOptions() + { + AppId = appCredentials.MicrosoftAppId, + ClientCertificate = cert, + }; + + await this.CreateConversationAsync(channelId, serviceUrl, new CertificateAppCredentials(options) as AppCredentials, conversationParameters, callback, cancellationToken); + } + + /// + public async Task CreateConversationUsingSecretAsync(string channelId, string serviceUrl, MicrosoftAppCredentials credentials, ConversationParameters conversationParameters, BotCallbackHandler callback, CancellationToken cancellationToken) + { + await this.CreateConversationAsync(channelId, serviceUrl, credentials, conversationParameters, callback, cancellationToken); + } + + /// + protected override async Task BuildCredentialsAsync(string appId, string oAuthScope = null) + { + appId = appId ?? throw new ArgumentNullException(nameof(appId)); + + if (this.certificateProvider.IsCertificateAuthenticationEnabled()) + { + var cert = await this.certificateProvider.GetCertificateAsync(appId); + var options = new CertificateAppCredentialsOptions() + { + AppId = appId, + ClientCertificate = cert, + OauthScope = oAuthScope, + }; + + var certificateAppCredentials = new CertificateAppCredentials(options) as AppCredentials; + return certificateAppCredentials; + } + else + { + return await base.BuildCredentialsAsync(appId, oAuthScope); + } } } } diff --git a/Source/CompanyCommunicator.Common/Adapter/ICCBotFrameworkHttpAdapter.cs b/Source/CompanyCommunicator.Common/Adapter/ICCBotFrameworkHttpAdapter.cs index 8c9c7409e..9897f8093 100644 --- a/Source/CompanyCommunicator.Common/Adapter/ICCBotFrameworkHttpAdapter.cs +++ b/Source/CompanyCommunicator.Common/Adapter/ICCBotFrameworkHttpAdapter.cs @@ -9,16 +9,17 @@ namespace Microsoft.Teams.Apps.CompanyCommunicator.Common.Adapter using System.Threading.Tasks; using Microsoft.Bot.Builder; using Microsoft.Bot.Builder.Integration; + using Microsoft.Bot.Builder.Integration.AspNet.Core; using Microsoft.Bot.Connector.Authentication; using Microsoft.Bot.Schema; /// /// Bot Framework Http Adapter interface. /// - public interface ICCBotFrameworkHttpAdapter : IAdapterIntegration + public interface ICCBotFrameworkHttpAdapter : IAdapterIntegration, IBotFrameworkHttpAdapter { /// - /// Creates a conversation on the specified channel. + /// Creates a conversation using app secret on the specified channel. /// /// The ID for the channel. /// The channel's service URL endpoint. @@ -27,6 +28,19 @@ public interface ICCBotFrameworkHttpAdapter : IAdapterIntegration /// The method to call for the resulting bot turn. /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. /// A task that represents the work queued to execute. - Task CreateConversationAsync(string channelId, string serviceUrl, MicrosoftAppCredentials credentials, ConversationParameters conversationParameters, BotCallbackHandler callback, CancellationToken cancellationToken); + Task CreateConversationUsingSecretAsync(string channelId, string serviceUrl, MicrosoftAppCredentials credentials, ConversationParameters conversationParameters, BotCallbackHandler callback, CancellationToken cancellationToken); + + /// + /// Creates a conversation using app certificate on the specified channel. + /// This method can be used to use certificates for authentication. + /// + /// The ID for the channel. + /// The channel's service URL endpoint. + /// The application credentials for the bot. + /// The conversation information to use to create the conversation. + /// The method to call for the resulting bot turn. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// A task that represents the work queued to execute. + Task CreateConversationUsingCertificateAsync(string channelId, string serviceUrl, AppCredentials appCredentials, ConversationParameters conversationParameters, BotCallbackHandler callback, CancellationToken cancellationToken); } } diff --git a/Source/CompanyCommunicator.Common/Constants.cs b/Source/CompanyCommunicator.Common/Constants.cs index 79cce3a14..ff60ede07 100644 --- a/Source/CompanyCommunicator.Common/Constants.cs +++ b/Source/CompanyCommunicator.Common/Constants.cs @@ -11,9 +11,9 @@ namespace Microsoft.Teams.Apps.CompanyCommunicator.Common public static class Constants { /// - /// get the group read all scope. + /// get the groupMember read all scope. /// - public const string ScopeGroupReadAll = "Group.Read.All"; + public const string ScopeGroupMemberReadAll = "GroupMember.Read.All"; /// /// AppCatalog Read All scope. diff --git a/Source/CompanyCommunicator.Common/Extensions/ServiceCollectionExtension.cs b/Source/CompanyCommunicator.Common/Extensions/ServiceCollectionExtension.cs new file mode 100644 index 000000000..7124bdecb --- /dev/null +++ b/Source/CompanyCommunicator.Common/Extensions/ServiceCollectionExtension.cs @@ -0,0 +1,123 @@ +// +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. +// + +namespace Microsoft.Teams.Apps.CompanyCommunicator.Common.Extensions +{ + using System; + using global::Azure.Core; + using global::Azure.Identity; + using global::Azure.Messaging.ServiceBus; + using global::Azure.Storage.Blobs; + using Microsoft.Extensions.Configuration; + using Microsoft.Extensions.DependencyInjection; + using Microsoft.Extensions.Options; + using Microsoft.Identity.Client; + using Microsoft.Teams.Apps.CompanyCommunicator.Common.Secrets; + using Microsoft.Teams.Apps.CompanyCommunicator.Common.Services.CommonBot; + + /// + /// Extension class for registering resources in DI container. + /// + public static class ServiceCollectionExtension + { + /// + /// Add Blob client dependency either using Managed identity or connection string. + /// + /// Collection of services. + /// boolean to indicate to use managed identity or connection string. + public static void AddBlobClient(this IServiceCollection services, bool useManagedIdentity) + { + // Setup blob client options. + var options = new BlobClientOptions(); + + // configure retries + options.Retry.MaxRetries = 5; // default is 3 + options.Retry.Mode = RetryMode.Exponential; // default is fixed retry policy + options.Retry.Delay = TimeSpan.FromSeconds(1); // default is 0.8s + + if (useManagedIdentity) + { + // Add using managed identities. + services.AddSingleton(sp => new BlobContainerClient( + GetBlobContainerUri(sp.GetService().GetValue("StorageAccountName")), + new DefaultAzureCredential(), + options)); + } + else + { + // Add using connection strings. + services.AddSingleton(sp => new BlobContainerClient( + sp.GetService().GetValue("StorageAccountConnectionString"), + Common.Constants.BlobContainerName, + options)); + } + } + + /// + /// Add Service Bus client dependency either using Managed identity or connection string. + /// + /// Collection of services. + /// boolean to indicate to use managed identity or connection string. + public static void AddServiceBusClient(this IServiceCollection services, bool useManagedIdentity) + { + if (useManagedIdentity) + { + // Adding using managed identities. + services.AddSingleton(sp => new ServiceBusClient( + sp.GetService().GetValue("ServiceBusNamespace"), + new DefaultAzureCredential())); + } + else + { + // Adding using connection strings. + services.AddSingleton(sp => new ServiceBusClient( + sp.GetService().GetValue("ServiceBusConnection"))); + } + } + + /// + /// Add Confidential client dependency to make graph calls. + /// + /// Collection of services. + /// boolean to indicate to use certificates or credentials. + public static void AddConfidentialClient(this IServiceCollection services, bool useCertificates) + { + if (useCertificates) + { + services.AddSingleton(provider => + { + var options = provider.GetRequiredService>(); + var certificateProvider = provider.GetRequiredService(); + var cert = certificateProvider.GetCertificateAsync(options.Value.ClientId).Result; + return ConfidentialClientApplicationBuilder + .Create(options.Value.ClientId) + .WithCertificate(cert) + .WithAuthority(new Uri($"https://login.microsoftonline.com/{options.Value.TenantId}")) + .Build(); + }); + } + else + { + services.AddSingleton(provider => + { + var options = provider.GetRequiredService>(); + return ConfidentialClientApplicationBuilder + .Create(options.Value.ClientId) + .WithClientSecret(options.Value.ClientSecret) + .WithAuthority(new Uri($"https://login.microsoftonline.com/{options.Value.TenantId}")) + .Build(); + }); + } + } + + private static Uri GetBlobContainerUri(string storageAccountName) + { + return new Uri(string.Format( + "https://{0}.blob.core.windows.net/{1}", + storageAccountName, + Common.Constants.BlobContainerName)); + } + } +} diff --git a/Source/CompanyCommunicator.Common/Microsoft.Teams.Apps.CompanyCommunicator.Common.csproj b/Source/CompanyCommunicator.Common/Microsoft.Teams.Apps.CompanyCommunicator.Common.csproj index a0d8efcc8..d860f5091 100644 --- a/Source/CompanyCommunicator.Common/Microsoft.Teams.Apps.CompanyCommunicator.Common.csproj +++ b/Source/CompanyCommunicator.Common/Microsoft.Teams.Apps.CompanyCommunicator.Common.csproj @@ -17,13 +17,17 @@ + + + + - + - + diff --git a/Source/CompanyCommunicator.Common/Secrets/Cache.cs b/Source/CompanyCommunicator.Common/Secrets/Cache.cs new file mode 100644 index 000000000..7e6edefb5 --- /dev/null +++ b/Source/CompanyCommunicator.Common/Secrets/Cache.cs @@ -0,0 +1,106 @@ +// +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. +// + +namespace Microsoft.Teams.Apps.CompanyCommunicator.Common.Secrets +{ + using System; + using System.Collections.Generic; + using System.Threading; + using System.Threading.Tasks; + using global::Azure; + + /// + /// Maintains a cache of items. + /// + /// Source: https://github.com/Azure/azure-sdk-for-net/blob/main/sdk/keyvault/samples/keyvaultproxy/src. + /// + internal class Cache : IDisposable + { + private readonly Dictionary cache = new Dictionary(StringComparer.OrdinalIgnoreCase); +#pragma warning disable CS8632 // The annotation for nullable reference types should only be used in code within a '#nullable' annotations context. + private SemaphoreSlim? semaphore = new SemaphoreSlim(1, 1); +#pragma warning restore CS8632 // The annotation for nullable reference types should only be used in code within a '#nullable' annotations context. + + /// + public void Dispose() + { + if (this.semaphore is { }) + { + this.semaphore.Dispose(); + this.semaphore = null; + } + } + + /// + /// Gets a valid or requests and caches a . + /// + /// Whether certain operations should be performed asynchronously. + /// The URI sans query parameters to cache. + /// The amount of time for which the cached item is valid. + /// The action to request a response. + /// A new . + internal async ValueTask GetOrAddAsync(bool isAsync, string uri, TimeSpan ttl, Func> action) + { + this.ThrowIfDisposed(); + + if (isAsync) + { + await this.semaphore!.WaitAsync().ConfigureAwait(false); + } + else + { + this.semaphore!.Wait(); + } + + try + { + // Try to get a valid cached response inside the lock before fetching. + if (this.cache.TryGetValue(uri, out CachedResponse cachedResponse) && cachedResponse.IsValid) + { + return await cachedResponse.CloneAsync(isAsync).ConfigureAwait(false); + } + + Response response = await action().ConfigureAwait(false); + if (response.Status == 200 && response.ContentStream is { }) + { + cachedResponse = await CachedResponse.CreateAsync(isAsync, response, ttl).ConfigureAwait(false); + this.cache[uri] = cachedResponse; + } + + return response; + } + finally + { + this.semaphore.Release(); + } + } + + /// + /// Clears the cache. + /// + internal void Clear() + { + this.ThrowIfDisposed(); + + this.semaphore!.Wait(); + try + { + this.cache.Clear(); + } + finally + { + this.semaphore.Release(); + } + } + + private void ThrowIfDisposed() + { + if (this.semaphore is null) + { + throw new ObjectDisposedException(nameof(this.semaphore)); + } + } + } +} \ No newline at end of file diff --git a/Source/CompanyCommunicator.Common/Secrets/CachedResponse.cs b/Source/CompanyCommunicator.Common/Secrets/CachedResponse.cs new file mode 100644 index 000000000..143f7bf5b --- /dev/null +++ b/Source/CompanyCommunicator.Common/Secrets/CachedResponse.cs @@ -0,0 +1,127 @@ +// +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. +// + +#nullable disable + +namespace Microsoft.Teams.Apps.CompanyCommunicator.Common.Secrets +{ + using System; + using System.Collections.Generic; + using System.IO; + using System.Threading.Tasks; + using global::Azure; + using global::Azure.Core; + + /// + /// A cached that is cloned and returned for subsequent requests. + /// + /// Source: https://github.com/Azure/azure-sdk-for-net/blob/main/sdk/keyvault/samples/keyvaultproxy/src. + /// + internal class CachedResponse : Response + { + private readonly ResponseHeaders headers; + private DateTimeOffset expires; + + private CachedResponse(int status, string reasonPhrase, ResponseHeaders headers) + { + this.Status = status; + this.ReasonPhrase = reasonPhrase; + + this.headers = headers; + } + + /// + public override int Status { get; } + + /// + public override string ReasonPhrase { get; } + + /// + public override Stream ContentStream { get; set; } + + /// + public override string ClientRequestId { get; set; } + + /// + /// Gets a value indicating whether this is still valid (has not expired). + /// + internal bool IsValid => DateTimeOffset.Now <= this.expires; + + /// + public override void Dispose() => this.ContentStream?.Dispose(); + + /// + /// Creates a new . + /// + /// Whether to copy the asynchronously. + /// The to copy. + /// The time to live. + /// A copied from the . + internal static async ValueTask CreateAsync(bool isAsync, Response response, TimeSpan ttl) + { + CachedResponse cachedResponse = await CloneAsync(isAsync, response).ConfigureAwait(false); + cachedResponse.expires = DateTimeOffset.Now + ttl; + + return cachedResponse; + } + + /// + /// Clones this into a new . + /// + /// Whether to copy the asynchronously. + /// A cloned . + internal async ValueTask CloneAsync(bool isAsync) => + await CloneAsync(isAsync, this).ConfigureAwait(false); + + /// + protected override bool ContainsHeader(string name) => this.headers.Contains(name); + + /// + protected override IEnumerable EnumerateHeaders() => this.headers; + + /// + protected override bool TryGetHeader(string name, out string value) => this.headers.TryGetValue(name, out value); + + /// + protected override bool TryGetHeaderValues(string name, out IEnumerable values) => this.headers.TryGetValues(name, out values); + + private static async ValueTask CloneAsync(bool isAsync, Response response) + { + CachedResponse cachedResponse = new CachedResponse(response.Status, response.ReasonPhrase, response.Headers) + { + ClientRequestId = response.ClientRequestId, + }; + + if (response.ContentStream is { }) + { + MemoryStream ms = new MemoryStream(); + cachedResponse.ContentStream = ms; + + if (isAsync) + { + await response.ContentStream.CopyToAsync(cachedResponse.ContentStream).ConfigureAwait(false); + } + else + { + response.ContentStream.CopyTo(cachedResponse.ContentStream); + } + + ms.Position = 0; + + // Reset the position if we can; otherwise, copy the buffer. + if (response.ContentStream.CanSeek) + { + response.ContentStream.Position = 0; + } + else + { + response.ContentStream = new MemoryStream(ms.ToArray()); + } + } + + return cachedResponse; + } + } +} \ No newline at end of file diff --git a/Source/CompanyCommunicator.Common/Secrets/CertificateProvider.cs b/Source/CompanyCommunicator.Common/Secrets/CertificateProvider.cs new file mode 100644 index 000000000..b6c70ae32 --- /dev/null +++ b/Source/CompanyCommunicator.Common/Secrets/CertificateProvider.cs @@ -0,0 +1,123 @@ +// +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. +// + +namespace Microsoft.Teams.Apps.CompanyCommunicator.Common.Secrets +{ + using System; + using System.Collections.Generic; + using System.IO; + using System.Security.Cryptography.X509Certificates; + using System.Threading.Tasks; + using global::Azure; + using global::Azure.Security.KeyVault.Certificates; + using Microsoft.Extensions.Logging; + using Microsoft.Extensions.Options; + using Microsoft.Teams.Apps.CompanyCommunicator.Common.Services.CommonBot; + + /// + /// This class implements ICertficateProvider, which is used to retrieve certificates. + /// + public class CertificateProvider : ICertificateProvider + { + private readonly Dictionary certificateNameMap; + private readonly bool useCertificate; + private readonly CertificateClient certificateClient; + private readonly ILogger logger; + + /// + /// Initializes a new instance of the class. + /// A constructor that accepts a map of bot id list and credentials. + /// + /// bot options. + /// certificate client. + /// The logger factory. + public CertificateProvider( + IOptions botOptions, + CertificateClient certificateClient, + ILoggerFactory loggerFactory) + { + botOptions = botOptions ?? throw new ArgumentNullException(nameof(botOptions)); + this.logger = loggerFactory?.CreateLogger() ?? throw new ArgumentNullException(nameof(loggerFactory)); + this.useCertificate = botOptions.Value.UseCertificate; + this.certificateClient = certificateClient ?? throw new ArgumentNullException(nameof(certificateClient)); + if (this.useCertificate) + { + this.certificateNameMap = this.CreateCertificateNameMap(botOptions.Value); + } + } + + /// + public async Task GetCertificateAsync(string appId) + { + appId = appId ?? throw new ArgumentNullException(nameof(appId)); + + var certificateName = this.certificateNameMap.ContainsKey(appId) ? this.certificateNameMap[appId] : null; + + if (string.IsNullOrEmpty(certificateName)) + { + throw new InvalidOperationException("Certificate name not found."); + } + + try + { + var response = await this.certificateClient.DownloadCertificateAsync(certificateName); + return response.Value; + } + catch (InvalidDataException exception) + { + this.logger.LogError(exception, $"Certificate not found. Cert name: {certificateName} "); + } + catch (RequestFailedException exception) + { + this.logger.LogError(exception, $"Failed to fetch certificate. ErrorCode: {exception.ErrorCode} Cert name: {certificateName}."); + } + catch (Exception exception) + { + this.logger.LogError(exception, $"Failed to fetch certificate. Cert name: {certificateName}."); + } + + throw new Exception($"Certificate not found. Cert name: {certificateName} "); + } + + /// + public bool IsCertificateAuthenticationEnabled() + { + return this.useCertificate; + } + + private Dictionary CreateCertificateNameMap(BotOptions botOptions) + { + var certificateNameMap = new Dictionary(); + if (string.IsNullOrEmpty(botOptions.UserAppId)) + { + throw new Exception("User app id not found."); + } + else + { + certificateNameMap.Add(botOptions.UserAppId, botOptions.UserAppCertName); + } + + if (string.IsNullOrEmpty(botOptions.AuthorAppId)) + { + throw new Exception("Author app id not found."); + } + else + { + certificateNameMap.Add(botOptions.AuthorAppId, botOptions.AuthorAppCertName); + } + + if (string.IsNullOrEmpty(botOptions.GraphAppId)) + { + throw new Exception("Graph app id not found."); + } + else + { + certificateNameMap.Add(botOptions.GraphAppId, botOptions.GraphAppCertName); + } + + return certificateNameMap; + } + } +} diff --git a/Source/CompanyCommunicator.Common/Secrets/ICertificateProvider.cs b/Source/CompanyCommunicator.Common/Secrets/ICertificateProvider.cs new file mode 100644 index 000000000..4b937df6a --- /dev/null +++ b/Source/CompanyCommunicator.Common/Secrets/ICertificateProvider.cs @@ -0,0 +1,29 @@ +// +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. +// + +namespace Microsoft.Teams.Apps.CompanyCommunicator.Common.Secrets +{ + using System.Security.Cryptography.X509Certificates; + using System.Threading.Tasks; + + /// + /// This instance is used to retrieve certificates. + /// + public interface ICertificateProvider + { + /// + /// Gets the certificate for the given app id. + /// + /// The Azure active directory Identifier. + /// Certificate. + Task GetCertificateAsync(string appId); + + /// + /// Checks if authentication is to be done using certificate. + /// + /// Boolean indicating if authentication type is certificate. + bool IsCertificateAuthenticationEnabled(); + } +} diff --git a/Source/CompanyCommunicator.Common/Secrets/KeyVaultProxy.cs b/Source/CompanyCommunicator.Common/Secrets/KeyVaultProxy.cs new file mode 100644 index 000000000..383cbaa2b --- /dev/null +++ b/Source/CompanyCommunicator.Common/Secrets/KeyVaultProxy.cs @@ -0,0 +1,119 @@ +// +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. +// + +namespace Microsoft.Teams.Apps.CompanyCommunicator.Common.Secrets +{ + using System; + using System.Threading.Tasks; + using global::Azure.Core; + using global::Azure.Core.Pipeline; + + /// + /// Cache GET requests for secrets, keys, or certificates for Azure Key Vault clients. + /// + /// Source: https://github.com/Azure/azure-sdk-for-net/blob/main/sdk/keyvault/samples/keyvaultproxy/src. + /// + public class KeyVaultProxy : HttpPipelinePolicy, IDisposable + { + private readonly Cache cache; + + /// + /// Initializes a new instance of the class. + /// + /// Optional time to live for cached responses. The default is 1 hour. + /// is less than 0. + public KeyVaultProxy(TimeSpan? ttl = null) + { + ttl ??= TimeSpan.FromHours(1); + if (ttl < TimeSpan.Zero) + { + throw new ArgumentOutOfRangeException(nameof(ttl)); + } + + this.Ttl = ttl.Value; + this.cache = new Cache(); + } + + /// + /// Gets the time to live for cached responses. + /// + public TimeSpan Ttl { get; internal set; } + + /// + /// Clears the in-memory cache. + /// + public void Clear() => this.cache.Clear(); + + /// + public override void Process(HttpMessage message, ReadOnlyMemory pipeline) => +#pragma warning disable AZC0102 // TaskExtensions.EnsureCompleted() is not in scope + this.ProcessAsync(false, message, pipeline).AsTask().GetAwaiter().GetResult(); +#pragma warning restore AZC0102 + + /// + public override async ValueTask ProcessAsync(HttpMessage message, ReadOnlyMemory pipeline) => + await this.ProcessAsync(true, message, pipeline).ConfigureAwait(false); + + /// + void IDisposable.Dispose() + { + this.cache.Dispose(); + GC.SuppressFinalize(this); + } + + /// + /// checks if uri is supported. + /// + /// Uri. + /// If uri is supported. + internal static bool IsSupported(string uri) + { + // Find the beginning of the path component after the scheme. + int pos = uri.IndexOf('/', 8); + if (pos > 0) + { + uri = uri.Substring(pos); + return uri.StartsWith("/secrets/", StringComparison.OrdinalIgnoreCase) + || uri.StartsWith("/keys/", StringComparison.OrdinalIgnoreCase) + || uri.StartsWith("/certificates/", StringComparison.OrdinalIgnoreCase); + } + + return false; + } + + private static async ValueTask ProcessNextAsync(bool isAsync, HttpMessage message, ReadOnlyMemory pipeline) + { + if (isAsync) + { + await ProcessNextAsync(message, pipeline).ConfigureAwait(false); + } + else + { + ProcessNext(message, pipeline); + } + } + + private async ValueTask ProcessAsync(bool isAsync, HttpMessage message, ReadOnlyMemory pipeline) + { + Request request = message.Request; + if (request.Method == RequestMethod.Get) + { + string uri = request.Uri.ToUri().GetLeftPart(UriPartial.Path); + if (IsSupported(uri)) + { + message.Response = await this.cache.GetOrAddAsync(isAsync, uri, this.Ttl, async () => + { + await ProcessNextAsync(isAsync, message, pipeline).ConfigureAwait(false); + return message.Response; + }).ConfigureAwait(false); + + return; + } + } + + await ProcessNextAsync(isAsync, message, pipeline).ConfigureAwait(false); + } + } +} \ No newline at end of file diff --git a/Source/CompanyCommunicator.Common/Secrets/SecretsRegistry.cs b/Source/CompanyCommunicator.Common/Secrets/SecretsRegistry.cs new file mode 100644 index 000000000..578f4cf29 --- /dev/null +++ b/Source/CompanyCommunicator.Common/Secrets/SecretsRegistry.cs @@ -0,0 +1,42 @@ +// +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. +// + +namespace Microsoft.Teams.Apps.CompanyCommunicator.Common.Secrets +{ + using System; + using global::Azure.Core; + using global::Azure.Identity; + using global::Azure.Security.KeyVault.Certificates; + using Microsoft.Extensions.DependencyInjection; + + /// + /// Register secrets dependencies. + /// + public static class SecretsRegistry + { + /// + /// Service Collection extension. + /// + /// Injects secrets provider. + /// + /// Service collection. + /// Key vault url. + /// the service collection. + public static IServiceCollection AddSecretsProvider(this IServiceCollection services, string keyVaultUrl) + { + if (string.IsNullOrEmpty(keyVaultUrl)) + { + throw new ArgumentNullException("KeyVault Url is null or empty."); + } + + var options = new CertificateClientOptions(); + options.AddPolicy(new KeyVaultProxy(), HttpPipelinePosition.PerCall); + services.AddSingleton(new CertificateClient(new Uri(keyVaultUrl), new DefaultAzureCredential(), options)); + services.AddSingleton(); + + return services; + } + } +} diff --git a/Source/CompanyCommunicator.Common/Services/CommonBot/AuthorAppCredentials.cs b/Source/CompanyCommunicator.Common/Services/CommonBot/AuthorAppCredentials.cs index aa0d217c5..6c9adbe91 100644 --- a/Source/CompanyCommunicator.Common/Services/CommonBot/AuthorAppCredentials.cs +++ b/Source/CompanyCommunicator.Common/Services/CommonBot/AuthorAppCredentials.cs @@ -5,6 +5,8 @@ namespace Microsoft.Teams.Apps.CompanyCommunicator.Common.Services.CommonBot { + using System; + using System.Threading.Tasks; using Microsoft.Bot.Connector.Authentication; using Microsoft.Extensions.Options; @@ -13,6 +15,8 @@ namespace Microsoft.Teams.Apps.CompanyCommunicator.Common.Services.CommonBot /// public class AuthorAppCredentials : MicrosoftAppCredentials { + private readonly bool useCertificate; + /// /// Initializes a new instance of the class. /// @@ -22,6 +26,17 @@ public AuthorAppCredentials(IOptions botOptions) appId: botOptions.Value.AuthorAppId, password: botOptions.Value.AuthorAppPassword) { + botOptions = botOptions ?? throw new ArgumentNullException(nameof(botOptions)); + this.useCertificate = botOptions.Value.UseCertificate; + } + + /// + /// Checks if authentication is to be done using certificate. + /// + /// Boolean indicating if authentication type is certifcate. + public bool IsCertificateAuthenticationEnabled() + { + return this.useCertificate; } } } diff --git a/Source/CompanyCommunicator.Common/Services/CommonBot/BotOptions.cs b/Source/CompanyCommunicator.Common/Services/CommonBot/BotOptions.cs index 36e089094..516eb4fa1 100644 --- a/Source/CompanyCommunicator.Common/Services/CommonBot/BotOptions.cs +++ b/Source/CompanyCommunicator.Common/Services/CommonBot/BotOptions.cs @@ -6,28 +6,53 @@ namespace Microsoft.Teams.Apps.CompanyCommunicator.Common.Services.CommonBot { /// - /// Options used for holding metadata for the bot. + /// Options used for holding meta data for the bot. /// public class BotOptions { /// - /// Gets or sets the Microsoft app ID for the user bot. + /// Gets or sets the User app ID for the user bot. /// public string UserAppId { get; set; } /// - /// Gets or sets the Microsoft app password for the user bot. + /// Gets or sets the User app password for the user bot. /// public string UserAppPassword { get; set; } /// - /// Gets or sets the Microsoft app ID for the author bot. + /// Gets or sets the Author app ID for the author bot. /// public string AuthorAppId { get; set; } /// - /// Gets or sets the Microsoft app password for the author bot. + /// Gets or sets the Author app password for the author bot. /// public string AuthorAppPassword { get; set; } + + /// + /// Gets or sets the Graph app ID for the author bot. + /// + public string GraphAppId { get; set; } + + /// + /// Gets or sets a value indicating whether to use certificates. + /// + public bool UseCertificate { get; set; } + + /// + /// Gets or sets the certificate name of the author app. + /// + public string AuthorAppCertName { get; set; } + + /// + /// Gets or sets the certificate name of the user app. + /// + public string UserAppCertName { get; set; } + + /// + /// Gets or sets the certificate name of the graph app. + /// + public string GraphAppCertName { get; set; } } } diff --git a/Source/CompanyCommunicator.Common/Services/CommonBot/UserAppCredentials.cs b/Source/CompanyCommunicator.Common/Services/CommonBot/UserAppCredentials.cs index d4d7051ec..6e6fe3cb9 100644 --- a/Source/CompanyCommunicator.Common/Services/CommonBot/UserAppCredentials.cs +++ b/Source/CompanyCommunicator.Common/Services/CommonBot/UserAppCredentials.cs @@ -5,6 +5,7 @@ namespace Microsoft.Teams.Apps.CompanyCommunicator.Common.Services.CommonBot { + using System; using Microsoft.Bot.Connector.Authentication; using Microsoft.Extensions.Options; @@ -13,6 +14,8 @@ namespace Microsoft.Teams.Apps.CompanyCommunicator.Common.Services.CommonBot /// public class UserAppCredentials : MicrosoftAppCredentials { + private readonly bool useCertificate; + /// /// Initializes a new instance of the class. /// @@ -22,6 +25,17 @@ public UserAppCredentials(IOptions botOptions) appId: botOptions.Value.UserAppId, password: botOptions.Value.UserAppPassword) { + botOptions = botOptions ?? throw new ArgumentNullException(nameof(botOptions)); + this.useCertificate = botOptions.Value.UseCertificate; + } + + /// + /// Checks if authentication is to be done using certificate. + /// + /// Boolean indicating if authentication type is certifcate. + public bool IsCertificateAuthenticationEnabled() + { + return this.useCertificate; } } } diff --git a/Source/CompanyCommunicator.Common/Services/MessageQueues/BaseQueue.cs b/Source/CompanyCommunicator.Common/Services/MessageQueues/BaseQueue.cs index 75d4f05a3..6195e1015 100644 --- a/Source/CompanyCommunicator.Common/Services/MessageQueues/BaseQueue.cs +++ b/Source/CompanyCommunicator.Common/Services/MessageQueues/BaseQueue.cs @@ -8,10 +8,8 @@ namespace Microsoft.Teams.Apps.CompanyCommunicator.Common.Services.MessageQueues using System; using System.Collections.Generic; using System.Linq; - using System.Text; using System.Threading.Tasks; - using Microsoft.Azure.ServiceBus; - using Microsoft.Azure.ServiceBus.Core; + using global::Azure.Messaging.ServiceBus; using Newtonsoft.Json; /// @@ -29,31 +27,49 @@ public abstract class BaseQueue : IBaseQueue /// The maximum number of messages that can be in one batch request to the service bus queue. /// public static readonly int MaxNumberOfMessagesInBatchRequest = 100; - - private readonly MessageSender messageSender; + private readonly ServiceBusSender sender; /// /// Initializes a new instance of the class. /// - /// The service bus connection string. + /// The service bus client. /// Azure service bus queue's name. - public BaseQueue(string serviceBusConnectionString, string queueName) + public BaseQueue(ServiceBusClient serviceBusClient, string queueName) { - this.messageSender = new MessageSender(serviceBusConnectionString, queueName); + if (serviceBusClient == null) + { + throw new ArgumentNullException(nameof(serviceBusClient)); + } + + if (string.IsNullOrEmpty(queueName)) + { + throw new ArgumentNullException(nameof(queueName)); + } + + this.sender = serviceBusClient.CreateSender(queueName); } /// public async Task SendAsync(T queueMessageContent) { - var messageBody = JsonConvert.SerializeObject(queueMessageContent); - var serviceBusMessage = new Message(Encoding.UTF8.GetBytes(messageBody)); + if (queueMessageContent == null) + { + throw new ArgumentNullException(nameof(queueMessageContent)); + } - await this.messageSender.SendAsync(serviceBusMessage); + var messageBody = JsonConvert.SerializeObject(queueMessageContent); + var serviceBusMessage = new ServiceBusMessage(messageBody); + await this.sender.SendMessageAsync(serviceBusMessage); } /// public async Task SendAsync(IEnumerable queueMessageContentBatch) { + if (queueMessageContentBatch == null) + { + throw new ArgumentNullException(nameof(queueMessageContentBatch)); + } + var queueMessageContentBatchAsList = queueMessageContentBatch.ToList(); // Check that the number of messages to add to the queue in the batch request is not @@ -68,23 +84,25 @@ public async Task SendAsync(IEnumerable queueMessageContentBatch) .Select(queueMessageContent => { var messageBody = JsonConvert.SerializeObject(queueMessageContent); - return new Message(Encoding.UTF8.GetBytes(messageBody)); + return new ServiceBusMessage(messageBody); }) .ToList(); - await this.messageSender.SendAsync(serviceBusMessages); + await this.sender.SendMessagesAsync(serviceBusMessages); } /// public async Task SendDelayedAsync(T queueMessageContent, double delayNumberOfSeconds) { - var messageBody = JsonConvert.SerializeObject(queueMessageContent); - var serviceBusMessage = new Message(Encoding.UTF8.GetBytes(messageBody)) + if (queueMessageContent == null) { - ScheduledEnqueueTimeUtc = DateTime.UtcNow + TimeSpan.FromSeconds(delayNumberOfSeconds), - }; + throw new ArgumentNullException(nameof(queueMessageContent)); + } - await this.messageSender.SendAsync(serviceBusMessage); + var messageBody = JsonConvert.SerializeObject(queueMessageContent); + var scheduledEnqueueTimeUtc = DateTime.UtcNow + TimeSpan.FromSeconds(delayNumberOfSeconds); + var serviceBusMessage = new ServiceBusMessage(messageBody); + await this.sender.ScheduleMessageAsync(serviceBusMessage, scheduledEnqueueTimeUtc); } } } diff --git a/Source/CompanyCommunicator.Common/Services/MessageQueues/DataQueue/DataQueue.cs b/Source/CompanyCommunicator.Common/Services/MessageQueues/DataQueue/DataQueue.cs index b30dc570a..20b7f939d 100644 --- a/Source/CompanyCommunicator.Common/Services/MessageQueues/DataQueue/DataQueue.cs +++ b/Source/CompanyCommunicator.Common/Services/MessageQueues/DataQueue/DataQueue.cs @@ -5,7 +5,7 @@ namespace Microsoft.Teams.Apps.CompanyCommunicator.Common.Services.MessageQueues.DataQueue { - using Microsoft.Extensions.Options; + using global::Azure.Messaging.ServiceBus; /// /// The message queue service connected to the "company-communicator-data" queue in Azure service bus. @@ -20,10 +20,10 @@ public class DataQueue : BaseQueue, IDataQueue /// /// Initializes a new instance of the class. /// - /// The message queue options. - public DataQueue(IOptions messageQueueOptions) + /// The service bus client. + public DataQueue(ServiceBusClient serviceBusClient) : base( - serviceBusConnectionString: messageQueueOptions.Value.ServiceBusConnection, + serviceBusClient: serviceBusClient, queueName: DataQueue.QueueName) { } diff --git a/Source/CompanyCommunicator.Common/Services/MessageQueues/ExportQueue/ExportQueue.cs b/Source/CompanyCommunicator.Common/Services/MessageQueues/ExportQueue/ExportQueue.cs index 2a8de8dca..1a9802974 100644 --- a/Source/CompanyCommunicator.Common/Services/MessageQueues/ExportQueue/ExportQueue.cs +++ b/Source/CompanyCommunicator.Common/Services/MessageQueues/ExportQueue/ExportQueue.cs @@ -5,7 +5,7 @@ namespace Microsoft.Teams.Apps.CompanyCommunicator.Common.Services.MessageQueues.ExportQueue { - using Microsoft.Extensions.Options; + using global::Azure.Messaging.ServiceBus; /// /// The message queue service connected to the "company-communicator-export" queue in Azure service bus. @@ -20,10 +20,10 @@ public class ExportQueue : BaseQueue, IExportQueue /// /// Initializes a new instance of the class. /// - /// The message queue options. - public ExportQueue(IOptions messageQueueOptions) + /// The service bus client. + public ExportQueue(ServiceBusClient serviceBusClient) : base( - serviceBusConnectionString: messageQueueOptions.Value.ServiceBusConnection, + serviceBusClient: serviceBusClient, queueName: ExportQueue.QueueName) { } diff --git a/Source/CompanyCommunicator.Common/Services/MessageQueues/MessageQueueOptions.cs b/Source/CompanyCommunicator.Common/Services/MessageQueues/MessageQueueOptions.cs deleted file mode 100644 index 0c2e0d3d9..000000000 --- a/Source/CompanyCommunicator.Common/Services/MessageQueues/MessageQueueOptions.cs +++ /dev/null @@ -1,18 +0,0 @@ -// -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. -// - -namespace Microsoft.Teams.Apps.CompanyCommunicator.Common.Services.MessageQueues -{ - /// - /// Options used for creating service bus message queues. - /// - public class MessageQueueOptions - { - /// - /// Gets or sets the service bus connection. - /// - public string ServiceBusConnection { get; set; } - } -} diff --git a/Source/CompanyCommunicator.Common/Services/MessageQueues/PrepareToSendQueue/PrepareToSendQueue.cs b/Source/CompanyCommunicator.Common/Services/MessageQueues/PrepareToSendQueue/PrepareToSendQueue.cs index 93db3847e..0606457a4 100644 --- a/Source/CompanyCommunicator.Common/Services/MessageQueues/PrepareToSendQueue/PrepareToSendQueue.cs +++ b/Source/CompanyCommunicator.Common/Services/MessageQueues/PrepareToSendQueue/PrepareToSendQueue.cs @@ -5,7 +5,7 @@ namespace Microsoft.Teams.Apps.CompanyCommunicator.Common.Services.MessageQueues.PrepareToSendQueue { - using Microsoft.Extensions.Options; + using global::Azure.Messaging.ServiceBus; /// /// The message queue service connected to the "company-communicator-prep" queue in Azure service bus. @@ -20,10 +20,10 @@ public class PrepareToSendQueue : BaseQueue, I /// /// Initializes a new instance of the class. /// - /// The message queue options. - public PrepareToSendQueue(IOptions messageQueueOptions) + /// The service bus client. + public PrepareToSendQueue(ServiceBusClient serviceBusClient) : base( - serviceBusConnectionString: messageQueueOptions.Value.ServiceBusConnection, + serviceBusClient: serviceBusClient, queueName: PrepareToSendQueue.QueueName) { } diff --git a/Source/CompanyCommunicator.Common/Services/MessageQueues/SendQueue/SendQueue.cs b/Source/CompanyCommunicator.Common/Services/MessageQueues/SendQueue/SendQueue.cs index d7de58568..53aec2e17 100644 --- a/Source/CompanyCommunicator.Common/Services/MessageQueues/SendQueue/SendQueue.cs +++ b/Source/CompanyCommunicator.Common/Services/MessageQueues/SendQueue/SendQueue.cs @@ -5,7 +5,7 @@ namespace Microsoft.Teams.Apps.CompanyCommunicator.Common.Services.MessageQueues.SendQueue { - using Microsoft.Extensions.Options; + using global::Azure.Messaging.ServiceBus; /// /// The message queue service connected to the "company-communicator-send" queue in Azure service bus. @@ -20,10 +20,10 @@ public class SendQueue : BaseQueue, ISendQueue /// /// Initializes a new instance of the class. /// - /// The message queue options. - public SendQueue(IOptions messageQueueOptions) + /// The service bus client. + public SendQueue(ServiceBusClient serviceBusClient) : base( - serviceBusConnectionString: messageQueueOptions.Value.ServiceBusConnection, + serviceBusClient: serviceBusClient, queueName: SendQueue.QueueName) { } diff --git a/Source/CompanyCommunicator.Common/Services/MicrosoftGraph/TeamWork/AppManagerService.cs b/Source/CompanyCommunicator.Common/Services/MicrosoftGraph/TeamWork/AppManagerService.cs index 41b5b58a4..854efd2d0 100644 --- a/Source/CompanyCommunicator.Common/Services/MicrosoftGraph/TeamWork/AppManagerService.cs +++ b/Source/CompanyCommunicator.Common/Services/MicrosoftGraph/TeamWork/AppManagerService.cs @@ -46,7 +46,7 @@ public async Task InstallAppForUserAsync(string appId, string userId) { AdditionalData = new Dictionary() { - { "teamsApp@odata.bind", $"{GraphConstants.BetaBaseUrl}/appCatalogs/teamsApps/{appId}" }, + { "teamsApp@odata.bind", $"{GraphConstants.V1BaseUrl}/appCatalogs/teamsApps/{appId}" }, }, }; diff --git a/Source/CompanyCommunicator.Common/Services/Teams/Conversations/ConversationService.cs b/Source/CompanyCommunicator.Common/Services/Teams/Conversations/ConversationService.cs index 843efb99f..a213b75ea 100644 --- a/Source/CompanyCommunicator.Common/Services/Teams/Conversations/ConversationService.cs +++ b/Source/CompanyCommunicator.Common/Services/Teams/Conversations/ConversationService.cs @@ -53,7 +53,8 @@ public async Task CreateUserConversationAsync( int maxAttempts, ILogger log) { - return await this.CreateConversationAsync(teamsUserId, tenantId, serviceUrl, maxAttempts, this.userAppCredentials, log); + var useCertificate = this.userAppCredentials.IsCertificateAuthenticationEnabled(); + return await this.CreateConversationAsync(teamsUserId, tenantId, serviceUrl, maxAttempts, this.userAppCredentials, useCertificate, log); } /// @@ -64,7 +65,8 @@ public async Task CreateAuthorConversationAsync( int maxAttempts, ILogger log) { - return await this.CreateConversationAsync(teamsUserId, tenantId, serviceUrl, maxAttempts, this.authorAppCredentials, log); + var useCertificate = this.authorAppCredentials.IsCertificateAuthenticationEnabled(); + return await this.CreateConversationAsync(teamsUserId, tenantId, serviceUrl, maxAttempts, this.authorAppCredentials, useCertificate, log); } private async Task CreateConversationAsync( @@ -73,6 +75,7 @@ private async Task CreateConversationAsync( string serviceUrl, int maxAttempts, MicrosoftAppCredentials credentials, + bool useCertificate, ILogger log) { if (string.IsNullOrEmpty(teamsUserId)) @@ -111,8 +114,29 @@ private async Task CreateConversationAsync( try { var retryPolicy = this.GetRetryPolicy(maxAttempts, log); - await retryPolicy.ExecuteAsync(async () => - await this.botAdapter.CreateConversationAsync( + if (useCertificate) + { + await retryPolicy.ExecuteAsync(async () => + await this.botAdapter.CreateConversationUsingCertificateAsync( + channelId: ConversationService.MicrosoftTeamsChannelId, + serviceUrl: serviceUrl, + appCredentials: credentials as AppCredentials, + conversationParameters: conversationParameters, + callback: (turnContext, cancellationToken) => + { + // Success. + response.Result = Result.Succeeded; + response.StatusCode = (int)HttpStatusCode.Created; + response.ConversationId = turnContext.Activity.Conversation.Id; + + return Task.CompletedTask; + }, + cancellationToken: CancellationToken.None)); + } + else + { + await retryPolicy.ExecuteAsync(async () => + await this.botAdapter.CreateConversationUsingSecretAsync( channelId: ConversationService.MicrosoftTeamsChannelId, serviceUrl: serviceUrl, credentials: credentials, @@ -127,6 +151,7 @@ await this.botAdapter.CreateConversationAsync( return Task.CompletedTask; }, cancellationToken: CancellationToken.None)); + } } catch (ErrorResponseException e) { diff --git a/Source/CompanyCommunicator.Common/Services/Teams/Messages/MessageService.cs b/Source/CompanyCommunicator.Common/Services/Teams/Messages/MessageService.cs index 467d471c2..13a11e182 100644 --- a/Source/CompanyCommunicator.Common/Services/Teams/Messages/MessageService.cs +++ b/Source/CompanyCommunicator.Common/Services/Teams/Messages/MessageService.cs @@ -9,10 +9,10 @@ namespace Microsoft.Teams.Apps.CompanyCommunicator.Common.Services.Teams using System.Net; using System.Threading; using System.Threading.Tasks; - using Microsoft.Bot.Builder.Integration.AspNet.Core; using Microsoft.Bot.Schema; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; + using Microsoft.Teams.Apps.CompanyCommunicator.Common.Adapter; using Microsoft.Teams.Apps.CompanyCommunicator.Common.Services.CommonBot; using Polly; using Polly.Contrib.WaitAndRetry; @@ -24,7 +24,7 @@ namespace Microsoft.Teams.Apps.CompanyCommunicator.Common.Services.Teams public class MessageService : IMessageService { private readonly string microsoftAppId; - private readonly BotFrameworkHttpAdapter botAdapter; + private readonly ICCBotFrameworkHttpAdapter botAdapter; /// /// Initializes a new instance of the class. @@ -33,7 +33,7 @@ public class MessageService : IMessageService /// The bot adapter. public MessageService( IOptions botOptions, - BotFrameworkHttpAdapter botAdapter) + ICCBotFrameworkHttpAdapter botAdapter) { this.microsoftAppId = botOptions?.Value?.UserAppId ?? throw new ArgumentNullException(nameof(botOptions)); this.botAdapter = botAdapter ?? throw new ArgumentNullException(nameof(botAdapter)); @@ -83,7 +83,7 @@ public async Task SendMessageAsync( }; await this.botAdapter.ContinueConversationAsync( - botAppId: this.microsoftAppId, + botId: this.microsoftAppId, reference: conversationReference, callback: async (turnContext, cancellationToken) => { diff --git a/Source/CompanyCommunicator.Common/Services/Teams/TeamMembers/TeamMembersService.cs b/Source/CompanyCommunicator.Common/Services/Teams/TeamMembers/TeamMembersService.cs index e5b1bafb8..186897b35 100644 --- a/Source/CompanyCommunicator.Common/Services/Teams/TeamMembers/TeamMembersService.cs +++ b/Source/CompanyCommunicator.Common/Services/Teams/TeamMembers/TeamMembersService.cs @@ -11,11 +11,11 @@ namespace Microsoft.Teams.Apps.CompanyCommunicator.Common.Services.Teams using System.Threading; using System.Threading.Tasks; using Microsoft.Bot.Builder; - using Microsoft.Bot.Builder.Integration.AspNet.Core; using Microsoft.Bot.Builder.Teams; using Microsoft.Bot.Schema; using Microsoft.Bot.Schema.Teams; using Microsoft.Extensions.Options; + using Microsoft.Teams.Apps.CompanyCommunicator.Common.Adapter; using Microsoft.Teams.Apps.CompanyCommunicator.Common.Extensions; using Microsoft.Teams.Apps.CompanyCommunicator.Common.Repositories.UserData; using Microsoft.Teams.Apps.CompanyCommunicator.Common.Services.CommonBot; @@ -25,7 +25,7 @@ namespace Microsoft.Teams.Apps.CompanyCommunicator.Common.Services.Teams /// public class TeamMembersService : ITeamMembersService { - private readonly BotFrameworkHttpAdapter botAdapter; + private readonly ICCBotFrameworkHttpAdapter botAdapter; private readonly string userAppId; private readonly string authorAppId; @@ -35,7 +35,7 @@ public class TeamMembersService : ITeamMembersService /// Bot adapter. /// Bot options. public TeamMembersService( - BotFrameworkHttpAdapter botAdapter, + ICCBotFrameworkHttpAdapter botAdapter, IOptions botOptions) { this.botAdapter = botAdapter ?? throw new ArgumentNullException(nameof(botAdapter)); diff --git a/Source/CompanyCommunicator.Data.Func/Services/FileCardServices/FileCardService.cs b/Source/CompanyCommunicator.Data.Func/Services/FileCardServices/FileCardService.cs index 4dcba7c6d..09683b4bb 100644 --- a/Source/CompanyCommunicator.Data.Func/Services/FileCardServices/FileCardService.cs +++ b/Source/CompanyCommunicator.Data.Func/Services/FileCardServices/FileCardService.cs @@ -9,10 +9,10 @@ namespace Microsoft.Teams.Apps.CompanyCommunicator.Data.Func.Services.FileCardSe using System.Threading; using System.Threading.Tasks; using Microsoft.Bot.Builder; - using Microsoft.Bot.Builder.Integration.AspNet.Core; using Microsoft.Bot.Schema; using Microsoft.Extensions.Localization; using Microsoft.Extensions.Options; + using Microsoft.Teams.Apps.CompanyCommunicator.Common.Adapter; using Microsoft.Teams.Apps.CompanyCommunicator.Common.Repositories.UserData; using Microsoft.Teams.Apps.CompanyCommunicator.Common.Resources; using Microsoft.Teams.Apps.CompanyCommunicator.Common.Services.CommonBot; @@ -25,7 +25,7 @@ public class FileCardService : IFileCardService { private readonly IUserDataRepository userDataRepository; private readonly string authorAppId; - private readonly BotFrameworkHttpAdapter botAdapter; + private readonly ICCBotFrameworkHttpAdapter botAdapter; private readonly IStringLocalizer localizer; /// @@ -37,7 +37,7 @@ public class FileCardService : IFileCardService /// Localization service. public FileCardService( IOptions botOptions, - BotFrameworkHttpAdapter botAdapter, + ICCBotFrameworkHttpAdapter botAdapter, IUserDataRepository userDataRepository, IStringLocalizer localizer) { @@ -74,7 +74,7 @@ public async Task DeleteAsync(string userId, string fileConsentId) int maxNumberOfAttempts = 10; await this.botAdapter.ContinueConversationAsync( - botAppId: this.authorAppId, + botId: this.authorAppId, reference: conversationReference, callback: async (turnContext, cancellationToken) => { diff --git a/Source/CompanyCommunicator.Data.Func/Startup.cs b/Source/CompanyCommunicator.Data.Func/Startup.cs index e30141950..e51061950 100644 --- a/Source/CompanyCommunicator.Data.Func/Startup.cs +++ b/Source/CompanyCommunicator.Data.Func/Startup.cs @@ -10,19 +10,20 @@ namespace Microsoft.Teams.Apps.CompanyCommunicator.Data.Func { using System; using System.Globalization; - using global::Azure.Storage.Blobs; using Microsoft.Azure.Functions.Extensions.DependencyInjection; using Microsoft.Bot.Builder.Integration.AspNet.Core; using Microsoft.Bot.Connector.Authentication; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; + using Microsoft.Teams.Apps.CompanyCommunicator.Common.Adapter; + using Microsoft.Teams.Apps.CompanyCommunicator.Common.Extensions; using Microsoft.Teams.Apps.CompanyCommunicator.Common.Repositories; using Microsoft.Teams.Apps.CompanyCommunicator.Common.Repositories.ExportData; using Microsoft.Teams.Apps.CompanyCommunicator.Common.Repositories.NotificationData; using Microsoft.Teams.Apps.CompanyCommunicator.Common.Repositories.SentNotificationData; using Microsoft.Teams.Apps.CompanyCommunicator.Common.Repositories.UserData; + using Microsoft.Teams.Apps.CompanyCommunicator.Common.Secrets; using Microsoft.Teams.Apps.CompanyCommunicator.Common.Services.CommonBot; - using Microsoft.Teams.Apps.CompanyCommunicator.Common.Services.MessageQueues; using Microsoft.Teams.Apps.CompanyCommunicator.Common.Services.MessageQueues.DataQueue; using Microsoft.Teams.Apps.CompanyCommunicator.Data.Func.Services.FileCardServices; using Microsoft.Teams.Apps.CompanyCommunicator.Data.Func.Services.NotificationDataServices; @@ -48,26 +49,18 @@ public override void Configure(IFunctionsHostBuilder builder) repositoryOptions.EnsureTableExists = !configuration.GetValue("IsItExpectedThatTableAlreadyExists", true); }); - builder.Services.AddOptions() - .Configure((messageQueueOptions, configuration) => - { - messageQueueOptions.ServiceBusConnection = - configuration.GetValue("ServiceBusConnection"); - }); builder.Services.AddOptions() .Configure((botOptions, configuration) => { - botOptions.UserAppId = - configuration.GetValue("UserAppId"); - - botOptions.UserAppPassword = - configuration.GetValue("UserAppPassword"); - - botOptions.AuthorAppId = - configuration.GetValue("AuthorAppId"); - - botOptions.AuthorAppPassword = - configuration.GetValue("AuthorAppPassword"); + botOptions.UserAppId = configuration.GetValue("UserAppId"); + botOptions.UserAppPassword = configuration.GetValue("UserAppPassword", string.Empty); + botOptions.UserAppCertName = configuration.GetValue("UserAppCertName", string.Empty); + botOptions.AuthorAppId = configuration.GetValue("AuthorAppId"); + botOptions.AuthorAppCertName = configuration.GetValue("AuthorAppPassword", string.Empty); + botOptions.AuthorAppCertName = configuration.GetValue("AuthorAppCertName", string.Empty); + botOptions.GraphAppId = configuration.GetValue("GraphAppId"); + botOptions.GraphAppCertName = configuration.GetValue("GraphAppCertName", string.Empty); + botOptions.UseCertificate = configuration.GetValue("UseCertificate", false); }); builder.Services.AddOptions() .Configure((cleanUpFileOptions, configuration) => @@ -87,21 +80,25 @@ public override void Configure(IFunctionsHostBuilder builder) builder.Services.AddLocalization(); + var useManagedIdentity = bool.Parse(Environment.GetEnvironmentVariable("UseManagedIdentity")); + builder.Services.AddBlobClient(useManagedIdentity); + builder.Services.AddServiceBusClient(useManagedIdentity); + // Set current culture. var culture = Environment.GetEnvironmentVariable("i18n:DefaultCulture"); CultureInfo.DefaultThreadCurrentCulture = new CultureInfo(culture); CultureInfo.DefaultThreadCurrentUICulture = new CultureInfo(culture); - // Add blob client. - builder.Services.AddSingleton(sp => new BlobContainerClient( - sp.GetService().GetValue("StorageAccountConnectionString"), - Common.Constants.BlobContainerName)); - // Add bot services. builder.Services.AddSingleton(); builder.Services.AddSingleton(); + builder.Services.AddSingleton(); builder.Services.AddSingleton(); + // Add Secrets. + var keyVaultUrl = Environment.GetEnvironmentVariable("KeyVault:Url"); + builder.Services.AddSecretsProvider(keyVaultUrl); + // Add services. builder.Services.AddSingleton(); diff --git a/Source/CompanyCommunicator.Prep.Func/Startup.cs b/Source/CompanyCommunicator.Prep.Func/Startup.cs index 10e490d13..85bbdd71b 100644 --- a/Source/CompanyCommunicator.Prep.Func/Startup.cs +++ b/Source/CompanyCommunicator.Prep.Func/Startup.cs @@ -15,21 +15,21 @@ namespace Microsoft.Teams.Apps.CompanyCommunicator.Prep.Func using Microsoft.Bot.Connector.Authentication; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; - using Microsoft.Extensions.Options; using Microsoft.Graph; using Microsoft.Identity.Client; using Microsoft.Teams.Apps.CompanyCommunicator.Common.Adapter; using Microsoft.Teams.Apps.CompanyCommunicator.Common.Clients; + using Microsoft.Teams.Apps.CompanyCommunicator.Common.Extensions; using Microsoft.Teams.Apps.CompanyCommunicator.Common.Repositories; using Microsoft.Teams.Apps.CompanyCommunicator.Common.Repositories.ExportData; using Microsoft.Teams.Apps.CompanyCommunicator.Common.Repositories.NotificationData; using Microsoft.Teams.Apps.CompanyCommunicator.Common.Repositories.SentNotificationData; using Microsoft.Teams.Apps.CompanyCommunicator.Common.Repositories.TeamData; using Microsoft.Teams.Apps.CompanyCommunicator.Common.Repositories.UserData; + using Microsoft.Teams.Apps.CompanyCommunicator.Common.Secrets; using Microsoft.Teams.Apps.CompanyCommunicator.Common.Services; using Microsoft.Teams.Apps.CompanyCommunicator.Common.Services.AdaptiveCard; using Microsoft.Teams.Apps.CompanyCommunicator.Common.Services.CommonBot; - using Microsoft.Teams.Apps.CompanyCommunicator.Common.Services.MessageQueues; using Microsoft.Teams.Apps.CompanyCommunicator.Common.Services.MessageQueues.DataQueue; using Microsoft.Teams.Apps.CompanyCommunicator.Common.Services.MessageQueues.ExportQueue; using Microsoft.Teams.Apps.CompanyCommunicator.Common.Services.MessageQueues.SendQueue; @@ -61,23 +61,27 @@ public override void Configure(IFunctionsHostBuilder builder) repositoryOptions.EnsureTableExists = !configuration.GetValue("IsItExpectedThatTableAlreadyExists", false); }); - builder.Services.AddOptions() - .Configure((messageQueueOptions, configuration) => - { - messageQueueOptions.ServiceBusConnection = - configuration.GetValue("ServiceBusConnection"); - }); builder.Services.AddOptions() .Configure((botOptions, configuration) => { botOptions.UserAppId = configuration.GetValue("UserAppId"); botOptions.UserAppPassword = - configuration.GetValue("UserAppPassword"); + configuration.GetValue("UserAppPassword", string.Empty); botOptions.AuthorAppId = configuration.GetValue("AuthorAppId"); botOptions.AuthorAppPassword = - configuration.GetValue("AuthorAppPassword"); + configuration.GetValue("AuthorAppPassword", string.Empty); + botOptions.GraphAppId = + configuration.GetValue("GraphAppId"); + botOptions.UseCertificate = + configuration.GetValue("UseCertificate", false); + botOptions.AuthorAppCertName = + configuration.GetValue("AuthorAppCertName", string.Empty); + botOptions.UserAppCertName = + configuration.GetValue("UserAppCertName", string.Empty); + botOptions.GraphAppCertName = + configuration.GetValue("GraphAppCertName", string.Empty); }); builder.Services.AddOptions() .Configure((dataQueueMessageOptions, configuration) => @@ -98,6 +102,10 @@ public override void Configure(IFunctionsHostBuilder builder) builder.Services.AddLocalization(); + var useManagedIdentity = bool.Parse(Environment.GetEnvironmentVariable("UseManagedIdentity")); + builder.Services.AddBlobClient(useManagedIdentity); + builder.Services.AddServiceBusClient(useManagedIdentity); + // Set current culture. var culture = Environment.GetEnvironmentVariable("i18n:DefaultCulture"); CultureInfo.DefaultThreadCurrentCulture = new CultureInfo(culture); @@ -136,6 +144,10 @@ public override void Configure(IFunctionsHostBuilder builder) builder.Services.AddTransient(); builder.Services.AddTransient(); + // Add Secrets. + var keyVaultUrl = Environment.GetEnvironmentVariable("KeyVault:Url"); + builder.Services.AddSecretsProvider(keyVaultUrl); + // Add graph services. this.AddGraphServices(builder); @@ -152,21 +164,15 @@ private void AddGraphServices(IFunctionsHostBuilder builder) builder.Services.AddOptions(). Configure((confidentialClientApplicationOptions, configuration) => { - confidentialClientApplicationOptions.ClientId = configuration.GetValue("AuthorAppId"); - confidentialClientApplicationOptions.ClientSecret = configuration.GetValue("AuthorAppPassword"); + confidentialClientApplicationOptions.ClientId = configuration.GetValue("GraphAppId"); + confidentialClientApplicationOptions.ClientSecret = configuration.GetValue("GraphAppPassword", string.Empty); confidentialClientApplicationOptions.TenantId = configuration.GetValue("TenantId"); }); // Graph Token Services - builder.Services.AddSingleton(provider => - { - var options = provider.GetRequiredService>(); - return ConfidentialClientApplicationBuilder - .Create(options.Value.ClientId) - .WithClientSecret(options.Value.ClientSecret) - .WithAuthority(new Uri($"https://login.microsoftonline.com/{options.Value.TenantId}")) - .Build(); - }); + var useClientCertificates = bool.Parse(Environment.GetEnvironmentVariable("UseCertificate") ?? "false"); + + builder.Services.AddConfidentialClient(useClientCertificates); builder.Services.AddSingleton(); diff --git a/Source/CompanyCommunicator.Send.Func/Startup.cs b/Source/CompanyCommunicator.Send.Func/Startup.cs index 2cc89028f..f44e8f979 100644 --- a/Source/CompanyCommunicator.Send.Func/Startup.cs +++ b/Source/CompanyCommunicator.Send.Func/Startup.cs @@ -15,11 +15,13 @@ namespace Microsoft.Teams.Apps.CompanyCommunicator.Send.Func using Microsoft.Bot.Connector.Authentication; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; + using Microsoft.Teams.Apps.CompanyCommunicator.Common.Adapter; + using Microsoft.Teams.Apps.CompanyCommunicator.Common.Extensions; using Microsoft.Teams.Apps.CompanyCommunicator.Common.Repositories; using Microsoft.Teams.Apps.CompanyCommunicator.Common.Repositories.NotificationData; using Microsoft.Teams.Apps.CompanyCommunicator.Common.Repositories.SentNotificationData; + using Microsoft.Teams.Apps.CompanyCommunicator.Common.Secrets; using Microsoft.Teams.Apps.CompanyCommunicator.Common.Services.CommonBot; - using Microsoft.Teams.Apps.CompanyCommunicator.Common.Services.MessageQueues; using Microsoft.Teams.Apps.CompanyCommunicator.Common.Services.MessageQueues.SendQueue; using Microsoft.Teams.Apps.CompanyCommunicator.Common.Services.Teams; using Microsoft.Teams.Apps.CompanyCommunicator.Send.Func.Services; @@ -45,11 +47,14 @@ public override void Configure(IFunctionsHostBuilder builder) builder.Services.AddOptions() .Configure((botOptions, configuration) => { - botOptions.UserAppId = - configuration.GetValue("UserAppId"); - - botOptions.UserAppPassword = - configuration.GetValue("UserAppPassword"); + botOptions.UserAppId = configuration.GetValue("UserAppId"); + botOptions.UserAppPassword = configuration.GetValue("UserAppPassword", string.Empty); + botOptions.UserAppCertName = configuration.GetValue("UserAppCertName", string.Empty); + botOptions.AuthorAppId = configuration.GetValue("AuthorAppId"); + botOptions.AuthorAppCertName = configuration.GetValue("AuthorAppCertName", string.Empty); + botOptions.GraphAppId = configuration.GetValue("GraphAppId"); + botOptions.GraphAppCertName = configuration.GetValue("GraphAppCertName", string.Empty); + botOptions.UseCertificate = configuration.GetValue("UseCertificate", false); }); builder.Services.AddOptions() .Configure((repositoryOptions, configuration) => @@ -63,15 +68,12 @@ public override void Configure(IFunctionsHostBuilder builder) repositoryOptions.EnsureTableExists = !configuration.GetValue("IsItExpectedThatTableAlreadyExists", true); }); - builder.Services.AddOptions() - .Configure((messageQueueOptions, configuration) => - { - messageQueueOptions.ServiceBusConnection = - configuration.GetValue("ServiceBusConnection"); - }); builder.Services.AddLocalization(); + var useManagedIdentity = bool.Parse(Environment.GetEnvironmentVariable("UseManagedIdentity")); + builder.Services.AddServiceBusClient(useManagedIdentity); + // Set current culture. var culture = Environment.GetEnvironmentVariable("i18n:DefaultCulture"); CultureInfo.DefaultThreadCurrentCulture = new CultureInfo(culture); @@ -80,6 +82,7 @@ public override void Configure(IFunctionsHostBuilder builder) // Add bot services. builder.Services.AddSingleton(); builder.Services.AddSingleton(); + builder.Services.AddSingleton(); builder.Services.AddSingleton(); // Add teams services. @@ -95,6 +98,10 @@ public override void Configure(IFunctionsHostBuilder builder) // Add the Notification service. builder.Services.AddTransient(); + + // Add Secrets. + var keyVaultUrl = Environment.GetEnvironmentVariable("KeyVault:Url"); + builder.Services.AddSecretsProvider(keyVaultUrl); } } } diff --git a/Source/CompanyCommunicator/Authentication/AuthenticationServiceCollectionExtensions.cs b/Source/CompanyCommunicator/Authentication/AuthenticationServiceCollectionExtensions.cs index 768257bfb..2032ed1a8 100644 --- a/Source/CompanyCommunicator/Authentication/AuthenticationServiceCollectionExtensions.cs +++ b/Source/CompanyCommunicator/Authentication/AuthenticationServiceCollectionExtensions.cs @@ -14,7 +14,6 @@ namespace Microsoft.Teams.Apps.CompanyCommunicator.Authentication using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Identity.Web; - using Microsoft.Identity.Web.TokenCacheProviders.InMemory; using Microsoft.IdentityModel.Tokens; /// @@ -35,7 +34,7 @@ public static void AddAuthentication( { AuthenticationServiceCollectionExtensions.RegisterAuthenticationServices(services, configuration, authenticationOptions); - AuthenticationServiceCollectionExtensions.RegisterAuthorizationPolicy(services); + AuthenticationServiceCollectionExtensions.RegisterAuthorizationPolicy(services, configuration); } // This method works specifically for single tenant application. @@ -45,18 +44,66 @@ private static void RegisterAuthenticationServices( AuthenticationOptions authenticationOptions) { AuthenticationServiceCollectionExtensions.ValidateAuthenticationOptions(authenticationOptions); + var azureADOptions = new AzureADOptions + { + Instance = authenticationOptions.AzureAdInstance, + TenantId = authenticationOptions.AzureAdTenantId, + ClientId = authenticationOptions.AzureAdClientId, + }; + var useCertificate = configuration.GetValue("UseCertificate"); + if (useCertificate) + { + RegisterAuthenticationServicesWithCertificate(services, configuration, authenticationOptions, azureADOptions); + } + else + { + RegisterAuthenticationServicesWithSecret(services, configuration, authenticationOptions, azureADOptions); + } + } - services.AddProtectedWebApi(configuration) - .AddProtectedWebApiCallsProtectedWebApi(configuration) - .AddInMemoryTokenCaches(); + private static void RegisterAuthenticationServicesWithCertificate( + IServiceCollection services, + IConfiguration configuration, + AuthenticationOptions authenticationOptions, + AzureADOptions azureADOptions) + { + services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) + .AddMicrosoftIdentityWebApi( + options => + { + options.Authority = $"{azureADOptions.Instance}{azureADOptions.TenantId}/v2.0"; + options.SaveToken = true; + options.TokenValidationParameters.ValidAudiences = AuthenticationServiceCollectionExtensions.GetValidAudiences(authenticationOptions); + options.TokenValidationParameters.AudienceValidator = AuthenticationServiceCollectionExtensions.AudienceValidator; + options.TokenValidationParameters.ValidIssuers = AuthenticationServiceCollectionExtensions.GetValidIssuers(authenticationOptions); + }, + microsoftIdentityOptions => + { + configuration.Bind("AzureAd", microsoftIdentityOptions); + microsoftIdentityOptions.ClientCertificates = new CertificateDescription[] + { + CertificateDescription.FromKeyVault(configuration.GetValue("KeyVault:Url"), configuration.GetValue("GraphAppCertName")), + }; + }) + .EnableTokenAcquisitionToCallDownstreamApi( + confidentialClientApplicationOptions => + { + configuration.Bind("AzureAd", confidentialClientApplicationOptions); + }) + .AddInMemoryTokenCaches(); + } + + private static void RegisterAuthenticationServicesWithSecret( + IServiceCollection services, + IConfiguration configuration, + AuthenticationOptions authenticationOptions, + AzureADOptions azureADOptions) + { + services.AddMicrosoftIdentityWebApiAuthentication(configuration) + .EnableTokenAcquisitionToCallDownstreamApi() + .AddInMemoryTokenCaches(); services.Configure(JwtBearerDefaults.AuthenticationScheme, options => { - var azureADOptions = new AzureADOptions - { - Instance = authenticationOptions.AzureAdInstance, - TenantId = authenticationOptions.AzureAdTenantId, - ClientId = authenticationOptions.AzureAdClientId, - }; options.Authority = $"{azureADOptions.Instance}{azureADOptions.TenantId}/v2.0"; options.SaveToken = true; options.TokenValidationParameters.ValidAudiences = AuthenticationServiceCollectionExtensions.GetValidAudiences(authenticationOptions); @@ -125,8 +172,9 @@ private static IEnumerable GetValidIssuers(AuthenticationOptions authent return validIssuers; } - private static void RegisterAuthorizationPolicy(IServiceCollection services) + private static void RegisterAuthorizationPolicy(IServiceCollection services, IConfiguration configuration) { + var graphGroupDatascope = configuration.GetValue("GroupsGraphScope"); services.AddAuthorization(options => { var mustContainUpnClaimRequirement = new MustBeValidUpnRequirement(); @@ -139,7 +187,7 @@ private static void RegisterAuthorizationPolicy(IServiceCollection services) options.AddPolicy( PolicyNames.MSGraphGroupDataPolicy, policyBuilder => policyBuilder - .AddRequirements(new MSGraphScopeRequirement(new string[] { Common.Constants.ScopeGroupReadAll })) + .AddRequirements(new MSGraphScopeRequirement(new string[] { graphGroupDatascope })) .RequireAuthenticatedUser() .Build()); }); diff --git a/Source/CompanyCommunicator/Authentication/GraphTokenProvider.cs b/Source/CompanyCommunicator/Authentication/GraphTokenProvider.cs index 181945882..b858cfdc6 100644 --- a/Source/CompanyCommunicator/Authentication/GraphTokenProvider.cs +++ b/Source/CompanyCommunicator/Authentication/GraphTokenProvider.cs @@ -52,12 +52,12 @@ private async Task GetAccessToken(string permissionType) if (permissionType.Equals(GraphPermissionType.Application.ToString(), StringComparison.CurrentCultureIgnoreCase)) { // we use MSAL.NET to get a token to call the API for application - accessToken = await this.tokenAcquisition.GetAccessTokenForAppAsync(new string[] { Common.Constants.ScopeDefault }); + accessToken = await this.tokenAcquisition.GetAccessTokenForAppAsync(Common.Constants.ScopeDefault); } else { // we use MSAL.NET to get a token to call the API On Behalf Of the current user - accessToken = await this.tokenAcquisition.GetAccessTokenForUserAsync(new string[] { Common.Constants.ScopeGroupReadAll, Common.Constants.ScopeAppCatalogReadAll }); + accessToken = await this.tokenAcquisition.GetAccessTokenForUserAsync(new string[] { Common.Constants.ScopeDefault }); } return accessToken; diff --git a/Source/CompanyCommunicator/Authentication/MSGraphScopeHandler.cs b/Source/CompanyCommunicator/Authentication/MSGraphScopeHandler.cs index 0527081bc..053f39690 100644 --- a/Source/CompanyCommunicator/Authentication/MSGraphScopeHandler.cs +++ b/Source/CompanyCommunicator/Authentication/MSGraphScopeHandler.cs @@ -51,7 +51,7 @@ protected override async Task HandleRequirementAsync(AuthorizationHandlerContext /// Indicate if access token has scope. private async Task HasScopesAsync(string[] scopes) { - var accessToken = await this.tokenAcquisition.GetAccessTokenForUserAsync(new[] { Common.Constants.ScopeGroupReadAll }); + var accessToken = await this.tokenAcquisition.GetAccessTokenForUserAsync(scopes); var tokenHandler = new JwtSecurityTokenHandler(); var securityToken = tokenHandler.ReadToken(accessToken) as JwtSecurityToken; var claimValue = securityToken.Claims diff --git a/Source/CompanyCommunicator/Bot/CompanyCommunicatorBotAdapter.cs b/Source/CompanyCommunicator/Bot/CompanyCommunicatorBotAdapter.cs index 5ef577da5..1f320f70a 100644 --- a/Source/CompanyCommunicator/Bot/CompanyCommunicatorBotAdapter.cs +++ b/Source/CompanyCommunicator/Bot/CompanyCommunicatorBotAdapter.cs @@ -5,25 +5,58 @@ namespace Microsoft.Teams.Apps.CompanyCommunicator.Bot { + using System; + using System.Threading.Tasks; using Microsoft.Bot.Builder.Integration.AspNet.Core; using Microsoft.Bot.Connector.Authentication; + using Microsoft.Teams.Apps.CompanyCommunicator.Common.Secrets; /// /// The Company Communicator Bot Adapter. /// public class CompanyCommunicatorBotAdapter : BotFrameworkHttpAdapter { + private readonly ICertificateProvider certificateProvider; + /// /// Initializes a new instance of the class. /// /// Credential provider service instance. /// Teams message filter middleware instance. + /// Certificate provider service instance. public CompanyCommunicatorBotAdapter( ICredentialProvider credentialProvider, - CompanyCommunicatorBotFilterMiddleware companyCommunicatorBotFilterMiddleware) + CompanyCommunicatorBotFilterMiddleware companyCommunicatorBotFilterMiddleware, + ICertificateProvider certificateProvider) : base(credentialProvider) { + companyCommunicatorBotFilterMiddleware = companyCommunicatorBotFilterMiddleware ?? throw new ArgumentNullException(nameof(companyCommunicatorBotFilterMiddleware)); + this.certificateProvider = certificateProvider ?? throw new ArgumentNullException(nameof(certificateProvider)); + + // Middleware this.Use(companyCommunicatorBotFilterMiddleware); } + + /// + protected override async Task BuildCredentialsAsync(string appId, string oAuthScope = null) + { + appId = appId ?? throw new ArgumentNullException(nameof(appId)); + + if (!this.certificateProvider.IsCertificateAuthenticationEnabled()) + { + return await base.BuildCredentialsAsync(appId, oAuthScope); + } + + var cert = await this.certificateProvider.GetCertificateAsync(appId); + var options = new CertificateAppCredentialsOptions() + { + AppId = appId, + ClientCertificate = cert, + OauthScope = oAuthScope, + }; + + var certificateAppCredentials = new CertificateAppCredentials(options) as AppCredentials; + return certificateAppCredentials; + } } } diff --git a/Source/CompanyCommunicator/ClientApp/package-lock.json b/Source/CompanyCommunicator/ClientApp/package-lock.json index f756ac4f2..c4d853990 100644 --- a/Source/CompanyCommunicator/ClientApp/package-lock.json +++ b/Source/CompanyCommunicator/ClientApp/package-lock.json @@ -1,6 +1,6 @@ { "name": "company-communicator", - "version": "4.1.5", + "version": "5.0.0", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -3501,9 +3501,9 @@ "integrity": "sha1-gTWEAhliqenm/QOflA0S9WynhZ4=" }, "ansi-regex": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", - "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==" + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" }, "ansi-styles": { "version": "3.2.1", @@ -3770,11 +3770,18 @@ "integrity": "sha512-V+Nq70NxKhYt89ArVcaNL9FDryB3vQOd+BFXZIfO3RP6rwtj+2yqqqdHEkacutglPaZLkJeuXKCjCJDMGPtPqg==" }, "axios": { - "version": "0.21.1", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.1.tgz", - "integrity": "sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA==", + "version": "0.21.4", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz", + "integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==", "requires": { - "follow-redirects": "^1.10.0" + "follow-redirects": "^1.14.0" + }, + "dependencies": { + "follow-redirects": { + "version": "1.14.4", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.4.tgz", + "integrity": "sha512-zwGkiSXC1MUJG/qmeIFH2HBJx9u0V46QGUe3YR1fXG8bXQxq7fLj0RjLZQ5nubr9qNJUZrH+xUcwXEoXNpfS+g==" + } } }, "axobject-query": { @@ -5453,12 +5460,12 @@ "integrity": "sha512-5pM/C1MIfoqhXa7k9PqSnrjj1SSZDakfyB1DZhdYyJoDUH+evGbsUg6/bpQapTJeSnYaj0rdzPUMeM33CvB0vw==" }, "cssnano": { - "version": "4.1.10", - "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-4.1.10.tgz", - "integrity": "sha512-5wny+F6H4/8RgNlaqab4ktc3e0/blKutmq8yNlBFXA//nSFFAqAngjNVRzUvCgYROULmZZUoosL/KSoZo5aUaQ==", + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-4.1.11.tgz", + "integrity": "sha512-6gZm2htn7xIPJOHY824ERgj8cNPgPxyCSnkXc4v7YvNW+TdVfzgngHcEhy/8D11kUWRUMbke+tC+AUcUsnMz2g==", "requires": { "cosmiconfig": "^5.0.0", - "cssnano-preset-default": "^4.0.7", + "cssnano-preset-default": "^4.0.8", "is-resolvable": "^1.0.0", "postcss": "^7.0.0" }, @@ -5474,6 +5481,43 @@ "parse-json": "^4.0.0" } }, + "cssnano-preset-default": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-4.0.8.tgz", + "integrity": "sha512-LdAyHuq+VRyeVREFmuxUZR1TXjQm8QQU/ktoo/x7bz+SdOge1YKc5eMN6pRW7YWBmyq59CqYba1dJ5cUukEjLQ==", + "requires": { + "css-declaration-sorter": "^4.0.1", + "cssnano-util-raw-cache": "^4.0.1", + "postcss": "^7.0.0", + "postcss-calc": "^7.0.1", + "postcss-colormin": "^4.0.3", + "postcss-convert-values": "^4.0.1", + "postcss-discard-comments": "^4.0.2", + "postcss-discard-duplicates": "^4.0.2", + "postcss-discard-empty": "^4.0.1", + "postcss-discard-overridden": "^4.0.1", + "postcss-merge-longhand": "^4.0.11", + "postcss-merge-rules": "^4.0.3", + "postcss-minify-font-values": "^4.0.2", + "postcss-minify-gradients": "^4.0.2", + "postcss-minify-params": "^4.0.2", + "postcss-minify-selectors": "^4.0.2", + "postcss-normalize-charset": "^4.0.1", + "postcss-normalize-display-values": "^4.0.2", + "postcss-normalize-positions": "^4.0.2", + "postcss-normalize-repeat-style": "^4.0.2", + "postcss-normalize-string": "^4.0.2", + "postcss-normalize-timing-functions": "^4.0.2", + "postcss-normalize-unicode": "^4.0.1", + "postcss-normalize-url": "^4.0.1", + "postcss-normalize-whitespace": "^4.0.2", + "postcss-ordered-values": "^4.1.2", + "postcss-reduce-initial": "^4.0.3", + "postcss-reduce-transforms": "^4.0.2", + "postcss-svgo": "^4.0.3", + "postcss-unique-selectors": "^4.0.1" + } + }, "import-fresh": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz", @@ -5492,6 +5536,21 @@ "json-parse-better-errors": "^1.0.1" } }, + "postcss-svgo": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-4.0.3.tgz", + "integrity": "sha512-NoRbrcMWTtUghzuKSoIm6XV+sJdvZ7GZSc3wdBN0W19FTtp2ko8NqLsgoh/m9CzNhU3KLPvQmjIwtaNFkaFTvw==", + "requires": { + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0", + "svgo": "^1.0.0" + } + }, + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==" + }, "resolve-from": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", @@ -5499,43 +5558,6 @@ } } }, - "cssnano-preset-default": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-4.0.7.tgz", - "integrity": "sha512-x0YHHx2h6p0fCl1zY9L9roD7rnlltugGu7zXSKQx6k2rYw0Hi3IqxcoAGF7u9Q5w1nt7vK0ulxV8Lo+EvllGsA==", - "requires": { - "css-declaration-sorter": "^4.0.1", - "cssnano-util-raw-cache": "^4.0.1", - "postcss": "^7.0.0", - "postcss-calc": "^7.0.1", - "postcss-colormin": "^4.0.3", - "postcss-convert-values": "^4.0.1", - "postcss-discard-comments": "^4.0.2", - "postcss-discard-duplicates": "^4.0.2", - "postcss-discard-empty": "^4.0.1", - "postcss-discard-overridden": "^4.0.1", - "postcss-merge-longhand": "^4.0.11", - "postcss-merge-rules": "^4.0.3", - "postcss-minify-font-values": "^4.0.2", - "postcss-minify-gradients": "^4.0.2", - "postcss-minify-params": "^4.0.2", - "postcss-minify-selectors": "^4.0.2", - "postcss-normalize-charset": "^4.0.1", - "postcss-normalize-display-values": "^4.0.2", - "postcss-normalize-positions": "^4.0.2", - "postcss-normalize-repeat-style": "^4.0.2", - "postcss-normalize-string": "^4.0.2", - "postcss-normalize-timing-functions": "^4.0.2", - "postcss-normalize-unicode": "^4.0.1", - "postcss-normalize-url": "^4.0.1", - "postcss-normalize-whitespace": "^4.0.2", - "postcss-ordered-values": "^4.1.2", - "postcss-reduce-initial": "^4.0.3", - "postcss-reduce-transforms": "^4.0.2", - "postcss-svgo": "^4.0.2", - "postcss-unique-selectors": "^4.0.1" - } - }, "cssnano-util-get-arguments": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/cssnano-util-get-arguments/-/cssnano-util-get-arguments-4.0.0.tgz", @@ -8217,11 +8239,6 @@ "resolved": "https://registry.npmjs.org/hsla-regex/-/hsla-regex-1.0.0.tgz", "integrity": "sha1-wc56MWjIxmFAM6S194d/OyJfnDg=" }, - "html-comment-regex": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/html-comment-regex/-/html-comment-regex-1.1.2.tgz", - "integrity": "sha512-P+M65QY2JQ5Y0G9KKdlDpo0zK+/OHptU5AaBwUfAIDJZk1MYf32Frm84EcOytfJE0t5JvkAnKlmjsXDnWzCJmQ==" - }, "html-encoding-sniffer": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz", @@ -9020,14 +9037,6 @@ "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.5.tgz", "integrity": "sha512-buY6VNRjhQMiF1qWDouloZlQbRhDPCebwxSjxMjxgemYT46YMd2NR0/H+fBhEfWX4A/w9TBJ+ol+okqJKFE6vQ==" }, - "is-svg": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-svg/-/is-svg-3.0.0.tgz", - "integrity": "sha512-gi4iHK53LR2ujhLVVj+37Ykh9GLqYHX6JOVXbLAucaG/Cqw9xwdFOjDM2qeifLs1sF1npXXFvDu0r5HNgCMrzQ==", - "requires": { - "html-comment-regex": "^1.1.0" - } - }, "is-symbol": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz", @@ -13223,24 +13232,6 @@ "util-deprecate": "^1.0.2" } }, - "postcss-svgo": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-4.0.2.tgz", - "integrity": "sha512-C6wyjo3VwFm0QgBy+Fu7gCYOkCmgmClghO+pjcxvrcBKtiKt0uCF+hvbMO1fyv5BMImRK90SMb+dwUnfbGd+jw==", - "requires": { - "is-svg": "^3.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0", - "svgo": "^1.0.0" - }, - "dependencies": { - "postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", - "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==" - } - } - }, "postcss-unique-selectors": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-4.0.1.tgz", @@ -14215,9 +14206,9 @@ "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, "nth-check": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.0.0.tgz", - "integrity": "sha512-i4sc/Kj8htBrAiH1viZ0TgU8Y5XqCaV/FziYK6TBczxmeKm3AEFWqqF3195yKudrarqy7Zu80Ra5dobFjn9X/Q==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.0.1.tgz", + "integrity": "sha512-it1vE95zF6dTT9lBsYbxvqh0Soy4SPowchj0UBGj/V6cTPnXXtQOPUbhZ6CmGzAD/rW22LQK6E96pcdJXk4A4w==", "requires": { "boolbase": "^1.0.0" } @@ -16047,9 +16038,9 @@ "integrity": "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==" }, "tmpl": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.4.tgz", - "integrity": "sha1-I2QN17QtAEM5ERQIIOXPRA5SHdE=" + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", + "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==" }, "to-arraybuffer": { "version": "1.0.1", diff --git a/Source/CompanyCommunicator/ClientApp/package.json b/Source/CompanyCommunicator/ClientApp/package.json index d164499ff..8cafb0c0a 100644 --- a/Source/CompanyCommunicator/ClientApp/package.json +++ b/Source/CompanyCommunicator/ClientApp/package.json @@ -1,12 +1,12 @@ { "name": "company-communicator", - "version": "4.1.5", + "version": "5.0.0", "private": true, "dependencies": { "@fluentui/react-northstar": "^0.52.0", "@microsoft/teams-js": "^1.4.2", "adaptivecards": "^1.2.0", - "axios": "^0.21.1", + "axios": "^0.21.4", "color-hash": "^1.0.3", "faker": "^4.1.0", "font-awesome": "^4.7.0", diff --git a/Source/CompanyCommunicator/Controllers/BotController.cs b/Source/CompanyCommunicator/Controllers/BotController.cs index 5609815f0..ce4e5bcee 100644 --- a/Source/CompanyCommunicator/Controllers/BotController.cs +++ b/Source/CompanyCommunicator/Controllers/BotController.cs @@ -11,6 +11,7 @@ namespace Microsoft.Teams.Apps.CompanyCommunicator.Controllers using Microsoft.Bot.Builder; using Microsoft.Bot.Builder.Integration.AspNet.Core; using Microsoft.Teams.Apps.CompanyCommunicator.Bot; + using Microsoft.Teams.Apps.CompanyCommunicator.Common.Adapter; /// /// Message controller for the bot. @@ -19,7 +20,7 @@ namespace Microsoft.Teams.Apps.CompanyCommunicator.Controllers [ApiController] public class BotController : ControllerBase { - private readonly BotFrameworkHttpAdapter adapter; + private readonly CompanyCommunicatorBotAdapter adapter; private readonly IBot authorBot; private readonly IBot userBot; diff --git a/Source/CompanyCommunicator/Microsoft.Teams.Apps.CompanyCommunicator.csproj b/Source/CompanyCommunicator/Microsoft.Teams.Apps.CompanyCommunicator.csproj index b5c4bd128..68d2eff93 100644 --- a/Source/CompanyCommunicator/Microsoft.Teams.Apps.CompanyCommunicator.csproj +++ b/Source/CompanyCommunicator/Microsoft.Teams.Apps.CompanyCommunicator.csproj @@ -10,16 +10,18 @@ + + - - + + - + all diff --git a/Source/CompanyCommunicator/Program.cs b/Source/CompanyCommunicator/Program.cs index 5bf9e51e0..88c5f43f3 100644 --- a/Source/CompanyCommunicator/Program.cs +++ b/Source/CompanyCommunicator/Program.cs @@ -5,7 +5,6 @@ namespace Microsoft.Teams.Apps.CompanyCommunicator { - using Microsoft.AspNetCore; using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Hosting; diff --git a/Source/CompanyCommunicator/Startup.cs b/Source/CompanyCommunicator/Startup.cs index ae4ebdb6d..067a2bf75 100644 --- a/Source/CompanyCommunicator/Startup.cs +++ b/Source/CompanyCommunicator/Startup.cs @@ -5,8 +5,8 @@ namespace Microsoft.Teams.Apps.CompanyCommunicator { + using System; using System.Net; - using global::Azure.Storage.Blobs; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Diagnostics; using Microsoft.AspNetCore.Hosting; @@ -21,16 +21,18 @@ namespace Microsoft.Teams.Apps.CompanyCommunicator using Microsoft.Graph; using Microsoft.Teams.Apps.CompanyCommunicator.Authentication; using Microsoft.Teams.Apps.CompanyCommunicator.Bot; + using Microsoft.Teams.Apps.CompanyCommunicator.Common.Adapter; + using Microsoft.Teams.Apps.CompanyCommunicator.Common.Extensions; using Microsoft.Teams.Apps.CompanyCommunicator.Common.Repositories; using Microsoft.Teams.Apps.CompanyCommunicator.Common.Repositories.ExportData; using Microsoft.Teams.Apps.CompanyCommunicator.Common.Repositories.NotificationData; using Microsoft.Teams.Apps.CompanyCommunicator.Common.Repositories.SentNotificationData; using Microsoft.Teams.Apps.CompanyCommunicator.Common.Repositories.TeamData; using Microsoft.Teams.Apps.CompanyCommunicator.Common.Repositories.UserData; + using Microsoft.Teams.Apps.CompanyCommunicator.Common.Secrets; using Microsoft.Teams.Apps.CompanyCommunicator.Common.Services; using Microsoft.Teams.Apps.CompanyCommunicator.Common.Services.AdaptiveCard; using Microsoft.Teams.Apps.CompanyCommunicator.Common.Services.CommonBot; - using Microsoft.Teams.Apps.CompanyCommunicator.Common.Services.MessageQueues; using Microsoft.Teams.Apps.CompanyCommunicator.Common.Services.MessageQueues.DataQueue; using Microsoft.Teams.Apps.CompanyCommunicator.Common.Services.MessageQueues.ExportQueue; using Microsoft.Teams.Apps.CompanyCommunicator.Common.Services.MessageQueues.PrepareToSendQueue; @@ -53,7 +55,7 @@ public class Startup /// IConfiguration instance. public Startup(IConfiguration configuration) { - this.Configuration = configuration; + this.Configuration = configuration ?? throw new ArgumentNullException(nameof(configuration)); } /// @@ -77,9 +79,14 @@ public void ConfigureServices(IServiceCollection services) .Configure((botOptions, configuration) => { botOptions.UserAppId = configuration.GetValue("UserAppId"); - botOptions.UserAppPassword = configuration.GetValue("UserAppPassword"); + botOptions.UserAppPassword = configuration.GetValue("UserAppPassword", string.Empty); botOptions.AuthorAppId = configuration.GetValue("AuthorAppId"); - botOptions.AuthorAppPassword = configuration.GetValue("AuthorAppPassword"); + botOptions.AuthorAppPassword = configuration.GetValue("AuthorAppPassword", string.Empty); + botOptions.UseCertificate = configuration.GetValue("UseCertificate", false); + botOptions.AuthorAppCertName = configuration.GetValue("AuthorAppCertName", string.Empty); + botOptions.UserAppCertName = configuration.GetValue("UserAppCertName", string.Empty); + botOptions.GraphAppId = configuration.GetValue("GraphAppId"); + botOptions.GraphAppCertName = configuration.GetValue("GraphAppCertName", string.Empty); }); services.AddOptions() .Configure((botFilterMiddlewareOptions, configuration) => @@ -99,12 +106,6 @@ public void ConfigureServices(IServiceCollection services) // tables exist. repositoryOptions.EnsureTableExists = true; }); - services.AddOptions() - .Configure((messageQueueOptions, configuration) => - { - messageQueueOptions.ServiceBusConnection = - configuration.GetValue("ServiceBusConnection"); - }); services.AddOptions() .Configure((dataQueueMessageOptions, configuration) => { @@ -140,10 +141,9 @@ public void ConfigureServices(IServiceCollection services) configuration.RootPath = "ClientApp/build"; }); - // Add blob client. - services.AddSingleton(sp => new BlobContainerClient( - sp.GetService().GetValue("StorageAccountConnectionString"), - Common.Constants.BlobContainerName)); + var useManagedIdentity = this.Configuration.GetValue("UseManagedIdentity"); + services.AddBlobClient(useManagedIdentity); + services.AddServiceBusClient(useManagedIdentity); // The bot needs an HttpClient to download and upload files. services.AddHttpClient(); @@ -174,6 +174,9 @@ public void ConfigureServices(IServiceCollection services) // Add draft notification preview services. services.AddSingleton(); + string keyVaultUrl = this.Configuration.GetValue("KeyVault:Url"); + services.AddSecretsProvider(keyVaultUrl); + // Add microsoft graph services. services.AddScoped(); services.AddScoped(); @@ -190,6 +193,7 @@ public void ConfigureServices(IServiceCollection services) services.AddTransient(); services.AddTransient(); services.AddTransient(); + services.AddTransient(); } /// diff --git a/Source/CompanyCommunicator/appsettings.json b/Source/CompanyCommunicator/appsettings.json index 64f2446d2..ab6f3f1b1 100644 --- a/Source/CompanyCommunicator/appsettings.json +++ b/Source/CompanyCommunicator/appsettings.json @@ -2,8 +2,8 @@ "AzureAd": { "Instance": "https://login.microsoftonline.com/", "TenantId": "[AzureAD Tenant Id]", - "ClientId": "[AzureAD Client Id]", - "ClientSecret": "[AzureAD Client Secret]", + "ClientId": "[GraphAppId]", + "ClientSecret": "[GraphAppPassword]", "ApplicationIdUri": "[AzureAD Application Id URI]", "ValidIssuers": "https://login.microsoftonline.com/TENANT_ID/v2.0,https://sts.windows.net/TENANT_ID/" }, @@ -19,18 +19,32 @@ "UserAppPassword": "[UserAppPassword]", "AuthorAppId": "[AuthorAppId]", "AuthorAppPassword": "[AuthorAppPassword]", + "GraphAppId": "[GraphAppId]", + "GraphAppPassword": "[GraphAppPassword]", "ServiceBusConnection": "[Service Bus Connection]", "StorageAccountConnectionString": "[Storage Account Connection String]", "DisableCreatorUpnCheck": "false", "AuthorizedCreatorUpns": "[upn list]", "DisableTenantFilter": "false", "AllowedTenants": "[tenant list]", + "WEBSITE_LOAD_CERTIFICATES": "*", + "UseCertificate": "true", + "AuthorAppCertName": "[AuthorAppCertName]", + "UserAppCertName": "[UserAppCertName]", + "GraphAppCertName": "[GraphAppCertName]", "ForceCompleteMessageDelayInSeconds": "86400", + "UseManagedIdentity": "true", + "ServiceBusNamespace": "[Service Bus Namespace]", + "StorageAccountName": "[Storage Account Name]", + "KeyVault": { + "Url": "https://{keyVaultName}.vault.azure.net" + }, "ApplicationInsights": { "InstrumentationKey": "" }, "i18n": { "DefaultCulture": "en-US", "SupportedCultures": "en-US" - } + }, + "GroupsGraphScope": "GroupMember.Read.All" } \ No newline at end of file diff --git a/Source/Test/CompanyCommunicator.Prep.Func.Test/Export/Activities/HandleExportFailureActivityTest.cs b/Source/Test/CompanyCommunicator.Prep.Func.Test/Export/Activities/HandleExportFailureActivityTest.cs index 9c79b71a6..4bf3b4553 100644 --- a/Source/Test/CompanyCommunicator.Prep.Func.Test/Export/Activities/HandleExportFailureActivityTest.cs +++ b/Source/Test/CompanyCommunicator.Prep.Func.Test/Export/Activities/HandleExportFailureActivityTest.cs @@ -37,6 +37,7 @@ public class HandleExportFailureActivityTest private readonly Mock> botOptions = new Mock>(); private readonly Mock botAdapter = new Mock(); private readonly Mock> localizer = new Mock>(); + private readonly Mock blobContainerClient = new Mock(); /// /// Constructor test for all parameters. diff --git a/Source/Test/CompanyCommunicator.Prep.Func.Test/Export/Activities/UploadActivityTest.cs b/Source/Test/CompanyCommunicator.Prep.Func.Test/Export/Activities/UploadActivityTest.cs index 455c40383..3726fa733 100644 --- a/Source/Test/CompanyCommunicator.Prep.Func.Test/Export/Activities/UploadActivityTest.cs +++ b/Source/Test/CompanyCommunicator.Prep.Func.Test/Export/Activities/UploadActivityTest.cs @@ -34,6 +34,7 @@ public class UploadActivityTest private readonly Mock storageClientFactory = new Mock(); private readonly Mock userDataStream = new Mock(); private readonly Mock> localizer = new Mock>(); + private readonly Mock blobContainerClientMock = new Mock(); private readonly string fileName = "fileName"; /// diff --git a/Wiki/Data-stores.md b/Wiki/Data-stores.md index 408cce2ca..0ef20757d 100644 --- a/Wiki/Data-stores.md +++ b/Wiki/Data-stores.md @@ -1,6 +1,7 @@ The app uses the following data stores: 1. Azure Storage Account 1. Application Insights +1. Azure Key vault All these resources are created in your Azure subscription. None are hosted directly by Microsoft. @@ -144,3 +145,18 @@ The Export Collection stores the export data. ## Application Insights See [Telemetry](Telemetry) + +## Azure Key vault + +The key vault stores the following data. + +| Value | Description +| --- | --- +| AuthorAppPassword | The client secret key of author bot. +| UserAppPassword | The client secret key of user bot. +| GraphAppSecret | The client secret key of graph app. +| Author app certificate | The Key vault certificate of author bot. +| User app certificate | The Key vault certificate of user bot. +| Graph app certificate | The Key vault certificate of graph app. +| ServiceBusConnectionString | The connection string of Service Bus Namespace. +| StorageAccountConnectionString | The connection string of Storage Account. diff --git a/Wiki/Deployment-guide-certificate.md b/Wiki/Deployment-guide-certificate.md new file mode 100644 index 000000000..a7ad1fd5f --- /dev/null +++ b/Wiki/Deployment-guide-certificate.md @@ -0,0 +1,358 @@ +- Deployment Guide + - [Prerequisites](#prerequisites) + - [Steps](#Deployment-Steps) + - [Register AD Application](#1-register-azure-ad-application) + - [Deploy to Azure subscription](#2-deploy-to-your-azure-subscription) + - [Set-up Authentication](#3-set-up-authentication) + - [Add Permissions to your app](#4-add-permissions-to-your-app) + - [Create the Teams app packages](#5-create-the-teams-app-packages) + - [Install the apps in Microsoft Teams](#6-install-the-apps-in-microsoft-teams) + - [Troubleshooting](#troubleshooting) +- - - + +# Prerequisites +The recommendation is to use [Deployment guide using powershell](Deployment-guide-powershell). + +To begin, you will need: +* An Azure subscription where you can create the following kinds of resources: + * App Service + * App Service Plan + * Bot Channels Registration + * Azure Function + * Azure Storage Account + * Service Bus + * Application Insights + * Azure Key vault +* An role to assign roles in Azure RBAC. To check if you have permission to do this, + * Goto the subscription page in Azure portal. Then, goto Access Control(IAM) and click on `View my access` button. + * Click on your `role` and in search permissions text box, search for `Microsoft.Authorization/roleAssignments/Write`. + * If your current role does not have the permission, then you can grant yourself the built in role `User Access Administrator` or create a custom role. + * Please follow this [link](https://docs.microsoft.com/en-us/azure/role-based-access-control/custom-roles#steps-to-create-a-custom-role) to create a custom role. Use this action `Microsoft.Authorization/roleAssignments/Write` in the custom role to assign roles in Azure RBAC. +* A team with the users who will be sending messages with this app. (You can add or remove team members later!) +* A copy of the Company Communicator app GitHub repo (https://github.com/OfficeDev/microsoft-teams-company-communicator-app) + +> **NOTE:** If you plan to use a custom domain name instead of relying on Azure Front Door, read the instructions [here](Custom-domain-option) first. + +- - - + +# Deployment Steps + +## 1. Register Azure AD application + +Register three Azure AD application in your tenant's directory: one for author bot, one for user bot and another for graph app. + +1. Log in to the Azure Portal for your subscription, and go to the [App registrations](https://portal.azure.com/#blade/Microsoft_AAD_IAM/ActiveDirectoryMenuBlade/RegisteredApps) blade. + +1. Click **New registration** to create an Azure AD application. + - **Name**: Name of your Teams App - if you are following the template for a default deployment, we recommend "Company Communicator User". + - **Supported account types**: Select "Accounts in any organizational directory" (*refer image below*). + - Leave the "Redirect URI" field blank for now. + + ![Azure AD app registration page](images/multitenant_app_creation.png) + +1. Click **Register** to complete the registration. + +1. When the app is registered, you'll be taken to the app's "Overview" page. Copy the **Application (client) ID**; we will need it later. Verify that the "Supported account types" is set to **Multiple organizations**. + + ![Azure AD app overview page](images/multitenant_app_overview_1.png) + +1. Go back to "App registrations", then repeat step no. 2 to create another Azure AD application for the author bot. + - **Name**: Name of your Teams App - if you are following the template for a default deployment, we recommend "Company Communicator Author". + - **Supported account types**: Select "Accounts in any organizational directory". + - Leave the "Redirect URI" field blank for now. + +1. Go back to "App registrations", then repeat step no. 2 to create another Azure AD application for the Microsoft Graph app. + - **Name**: Name of your Teams App - if you are following the template for a default deployment, we recommend "Company Communicator App". + - **Supported account types**: Select "Accounts in this organizational directory only(Default Directory only - Single tenant)". + - Leave the "Redirect URI" field blank for now. + + + At this point you should have the following 4 values: + 1. Application (client) ID for the user bot. + 2. Directory (tenant) ID. + 3. Application (client) ID for the author bot. + 4. Application (client) ID for the Microsoft Graph App. + + We recommend that you copy the values, we will need them later. + + ![Azure AD app overview page](images/multitenant_app_overview_2.png) + +## 2. Deploy to your Azure subscription +1. Click on the **Deploy to Azure** button below. + + [![Deploy to Azure](https://azuredeploy.net/deploybutton.png)](https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FOfficeDev%2Fmicrosoft-teams-company-communicator-app%2Fmaster%2FDeployment%2Fazuredeploywithcert.json) + +1. When prompted, log in to your Azure subscription. + +1. Azure will create a "Custom deployment" based on the Company Communicator ARM template and ask you to fill in the template parameters. + + > **Note:** Please ensure that you don't use underscore (_) or space in any of the field values otherwise the deployment may fail. + +1. Select a subscription and a resource group. + * We recommend creating a new resource group. + * The resource group location MUST be in a datacenter that supports all the following: + * Storage Accounts + * Application Insights + * Azure Functions + * Service Bus + * App Service + + For an up-to-date list of datacenters that support the above, click [here](https://azure.microsoft.com/en-us/global-infrastructure/services/?products=storage,app-service,monitor,service-bus,functions) + +1. Enter a **Base Resource Name**, which the template uses to generate names for the other resources. + * The `[Base Resource Name]` must be available. For example, if you select `contosocommunicator` as the base name, the name `contosocommunicator` must be available (not taken); otherwise, the deployment will fail with a Conflict error. + * Remember the base resource name that you selected. We will need it later. + +1. Update the following fields in the template: + 1. **User Client ID**: The application (client) ID of the Microsoft Teams user bot app. (from Step 1) + 2. **User App Certificate Name**: Provide the name for creating the new certificate of user bot Azure AD app in Azure Key vault + 3. **Tenant Id**: The tenant ID. (from Step 1) + 4. **Author Client ID**: The application (client) ID of the Microsoft Teams author bot app. (from Step 1) + 5. **Author App Certificate Name**: Provide the name for creating the new certificate of author bot Azure AD app in Azure Key vault + 6. **Microsoft Graph App Client ID**: The application (client) ID of the Microsoft Graph Azure AD app. (from Step 1) + 7. **Microsoft Graph App Certificate Name**: Provide the name for creating the new certificate of Microsoft Graph Azure AD app in Azure Key vault + 8. **Proactively Install User App [Optional]**: Default value is `true`. You may set it to `false` if you want to disable the feature. + 9. **User App ExternalId [Optional]**: Default value is `148a66bb-e83d-425a-927d-09f4299a9274`. This **MUST** be the same `id` that is in the Teams app manifest for the user app. + 10. **Service Bus Web App Role Name Guid [Optional]**: Default value is `958380b3-630d-4823-b933-f59d92cdcada`. This **MUST** be the same `id` per app deployment. + + > **Note:** Make sure to keep the same values for an upgrade. Please change the role name GUIDs in case of another Company Communicator Deployment in same subscription. + + 11. **Service Bus Prep Func Role Name Guid [Optional]**: Default value is `ce6ca916-08e9-4639-bfbe-9d098baf42ca`. This **MUST** be the same `id` per app deployment. + 12. **Service Bus Send Func Role Name Guid [Optional]**: Default value is `960365a2-c7bf-4ff3-8887-efa86fe4a163`. This **MUST** be the same `id` per app deployment. + 13. **Service Bus Data Func Role Name Guid [Optional]**: Default value is `d42703bc-421d-4d98-bc4d-cd2bb16e5b0a`. This **MUST** be the same `id` per app deployment. + 14. **Storage Account Web App Role Name Guid [Optional]**: Default value is `edd0cc48-2cf7-490e-99e8-131311e42030`. This **MUST** be the same `id` per app deployment. + 15. **Storage Account Prep Func Role Name Guid [Optional]**: Default value is `9332a9e9-93f4-48d9-8121-d279f30a732e`. This **MUST** be the same `id` per app deployment. + 16. **Storage Account Data Func Role Name Guid [Optional]**: Default value is `5b67af51-4a98-47e1-9d22-745069f51a13`. This **MUST** be the same `id` per app deployment. + 17. **DefaultCulture [Optional]**: By default the application uses `en-US` locale. You can choose the locale from the list, if you wish to use the app in different locale.Also, you may add/update the resources for other locales and update this configuration if desired. + 18. **SupportedCultures [Optional]**: This is the list of locales that application supports currently.You may add/update the resources for other locales and update this configuration if desired. + + + > **Note:** Make sure that the values are copied as-is, with no extra spaces. The template checks that GUIDs are exactly 36 characters. + + > **Note:** If your Azure subscription is in a different tenant than the tenant where you want to install the Teams App, please update the `Tenant Id` field with the tenant where you want to install the Teams App. + +1. Update the "Sender UPN List", which is a semicolon-delimited list of users (Authors) who will be allowed to send messages using the Company Communicator. + * For example, to allow Megan Bowen (meganb@contoso.com) and Adele Vance (adelev@contoso.com) to send messages, set this parameter to `meganb@contoso.com;adelev@contoso.com`. + * You can change this list later by going to the App Service's "Configuration" blade. + +1. If you wish to change the app name, description, and icon from the defaults, modify the corresponding template parameters. + +1. Agree to the Azure terms and conditions by clicking on the check box "I agree to the terms and conditions stated above" located at the bottom of the page. + +1. Click on "Purchase" to start the deployment. + +1. Wait for the deployment to finish. You can check the progress of the deployment from the "Notifications" pane of the Azure Portal. It may take **up to an hour** for the deployment to finish. + + > If the deployment fails, see [this section](https://github.com/OfficeDev/microsoft-teams-company-communicator-app/wiki/Troubleshooting#1-code-deployment-failure) of the Troubleshooting guide. + +1. Once the deployment is successfully completed, go to the deployment's "Outputs" tab, and note down the follwing values. We will need them later. + * **keyVaultName:** This is the Key Vault Name for the Company Communicator app. For the following steps, it will be referred to as `%keyVaultName%`. + * **authorBotId:** This is the Microsoft Application ID for the Company Communicator app. For the following steps, it will be referred to as `%authorBotId%`. + * **userBotId:** This is the Microsoft Application ID for the Company Communicator app. For the following steps, it will be referred to as `%userBotId%`. + * **appDomain:** This is the base domain for the Company Communicator app. For the following steps, it will be referred to as `%appDomain%`. + +> **IMPORTANT:** If you plan to use a custom domain name instead of relying on Azure Front Door, read the instructions [here](Custom-domain-option) before continuing any further. + +## 3. Create Key vault Certificate +1. On the Key vault page, select **Certificates**. +3. Click on **Generate/Import**. +3. On the **Create a certificate** screen choose the following values: + - **Method of Certificate Creation**: Generate. + - **Certificate Name**: AuthorAppCertificateName. This should be the same value given in step no. 2. + - **Subject**: CN=`%appDomain%`. + - Leave the other values to their defaults. (By default, if you don't specify anything special in Advanced policy, it'll be usable as a client auth certificate.) +4. Click **Create**. + +Once that you receive the message that the certificate has been successfully created, you may click on it on the list. You can then see some of the properties. If you click on the current version, you can see the value you specified in the previous step. + +![Certificate properties](images/create-certificate.png) + +Please repeat the steps for User bot certificate and Microsoft Graph app certificate. + +## 4. Export Certificate from Key Vault + +Download the certificate for all apps i.e. Author Bot, User Bot, Microsoft Graph app. + +You can download by Clicking "Download in CER format" button. +![Export Certificate](images/export-cert.png) + +## 5. Upload Certificate Azure AD App + +1. Go to **App Registrations** page [here](https://portal.azure.com/#blade/Microsoft_AAD_IAM/ActiveDirectoryMenuBlade/RegisteredApps) and open the Microsoft Graph Azure AD app you created (in Step 1) from the application list. + +2. On the side rail in the Manage section, navigate to the "Certificates & secrets" section. In the Certificates section, click on "Upload certificate". Select the certificate file downloaded in Step 4 for the Graph Azure AD app and click on Add. + +3. Please repeat the same for Author app and User app and upload the respective certificate downloaded in Step 3. + +## 6. Import Certificates from Key Vault to app and functions. + +1. Go to **App Service** page created as part of this deployment. +1. From the left navigation of your app, **select TLS/SSL settings > Private Key Certificates (.pfx) > Import Key Vault Certificate** +![Import Key Vault Certificate](images/import-key-vault-cert.png) +1. Use the following table to help you select the certificate. + + | Setting | Description | + |-|-| + | Subscription | The subscription that the Key Vault belongs to. | + | Key Vault | The vault with the certificate you want to import. | + | Certificate | Select from the list of PKCS12 certificates in the vault. All PKCS12 certificates in the vault are listed with their thumbprints, but not all are supported in App Service. | + +1. When the operation completes, you see the certificate in the **Private Key Certificates** list. +![Import Key Vault certificate finished](images/import-app-service-cert-finished.png) + +1. Please import all the certificates from the Key Vault. +1. Repeat the above steps for the function apps. + +> NOTE : If you update your certificate in Key Vault with a new certificate, App Service automatically syncs your certificate within 24 hours. + +## 7. Set-up Authentication + +1. Note that you have the `%authorBotId%`, `%userBotId%` and `%appDomain%` values from the previous step (Step 2). + + > If do not have these values, refer [this section](https://github.com/OfficeDev/microsoft-teams-company-communicator-app/wiki/Troubleshooting#2-forgetting-the-botId-or-appDomain) of the Troubleshooting guide for steps to get these values. + +1. Go to **App Registrations** page [here](https://portal.azure.com/#blade/Microsoft_AAD_IAM/ActiveDirectoryMenuBlade/RegisteredApps) and open the Microsoft Graph Azure AD app you created (in Step 1) from the application list. + + > NOTE: This step is to set-up authentication for Microsoft Graph Azure AD app. + +1. Under **Manage**, click on **Authentication** to bring up authentication settings. + + 1. Add a new entry to **Redirect URIs**: + - **Type**: Web + - **Redirect URI**: Enter `https://%appDomain%/signin-simple-end` for the URL e.g. `https://appName.azurefd.net/signin-simple-end` + + 1. Under **Implicit grant**, check **ID tokens**. + + 1. Click **Save** to commit your changes. + +1. Back under **Manage**, click on **Expose an API**. + + 1. Click on the **Set** link next to **Application ID URI**, and change the value to `api://%appDomain%` e.g. `api://appName.azurefd.net`. + + 1. Click **Save** to commit your changes. + + 1. Click on **Add a scope**, under **Scopes defined by this API**. In the flyout that appears, enter the following values: + * **Scope name:** access_as_user + * **Who can consent?:** Admins and users + * **Admin and user consent display name:** Access the API as the current logged-in user + * **Admin and user consent description:** Access the API as the current logged-in user + + 1. Click **Add scope** to commit your changes. + + 1. Click **Add a client application**, under **Authorized client applications**. In the flyout that appears, enter the following values: + * **Client ID**: `5e3ce6c0-2b1f-4285-8d4b-75ee78787346` + * **Authorized scopes**: Select the scope that ends with `access_as_user`. (There should only be 1 scope in this list.) + + 1. Click **Add application** to commit your changes. + + 1. **Repeat the previous two steps**, but with client ID = `1fec8e78-bce4-4aaf-ab1b-5451cc387264`. After this step you should have **two** client applications (`5e3ce6c0-2b1f-4285-8d4b-75ee78787346` and `1fec8e78-bce4-4aaf-ab1b-5451cc387264`) listed under **Authorized client applications**. + +1. Back under **Manage**, click on **Manifest**. + + 1. In the editor that appears, find the `optionalClaims` property in the JSON Azure AD application manifest, and replace it with the following block: + ``` + "optionalClaims": { + "idToken": [], + "accessToken": [ + { + "name": "upn", + "source": null, + "essential": false, + "additionalProperties": [] + } + ], + "saml2Token": [] + }, + ``` + + 2. Click **Save** to commit your changes. + +## 8. Add Permissions to your Microsoft Graph Azure AD app + +Continuing from the Microsoft Graph Azure AD app registration page where we ended Step 3. + +1. Select **API Permissions** blade from the left hand side. + +2. Click on **Add a permission** button to add permission to your app. + +3. In Microsoft APIs under Select an API label, select the particular service and give the following permissions, + + * Under **Commonly used Microsoft APIs**, + + * Select “Microsoft Graph”, then select **Delegated permissions** and check the following permissions, + 1. **GroupMember.Read.All** + 2. **AppCatalog.Read.All** + + * then select **Application permissions** and check the following permissions, + 1. **GroupMember.Read.All** + 2. **User.Read.All** + 3. **TeamsAppInstallation.ReadWriteForUser.All** + + * Click on **Add Permissions** to commit your changes. + + ![Azure AD API permissions](images/multitenant_app_permissions_1.png) + ![Azure AD API permissions](images/multitenant_app_permissions_2.png) + + > Please refer to [Solution overview](https://github.com/OfficeDev/microsoft-teams-company-communicator-app/wiki/Solution-overview#microsoft-graph-api) for more details about the above permissions. + +4. If you are logged in as the Global Administrator, click on the “Grant admin consent for %tenant-name%” button to grant admin consent, else inform your Admin to do the same through the portal. +
+ Alternatively you may follow the steps below: + - Prepare link - https://login.microsoftonline.com/common/adminconsent?client_id=%appId%. Replace the `%appId%` with the `Application (client) ID` of Microsoft Graph Azure AD app (from above). + - Global Administrator can grant consent using the link above. + +## 9. Create the Teams app packages + +Company communicator app comes with 2 applications – Author, User. The Author application is intended for employees who create and send messages in the organization, and the User application is intended for employees who receive the messages. + +Create two Teams app packages: one to be installed to an Authors team and other for recipients to install personally and/or to teams. + +1. Make sure you have cloned the app repository locally. + +1. Open the `Manifest\manifest_authors.json` file in a text editor. + +1. Change the placeholder fields in the manifest to values appropriate for your organization. + * `developer.name` ([What's this?](https://docs.microsoft.com/en-us/microsoftteams/platform/resources/schema/manifest-schema#developer)) + * `developer.websiteUrl` + * `developer.privacyUrl` + * `developer.termsOfUseUrl` + +1. Change the `<>` placholder in the configurationUrl setting to be the `%appDomain%` value e.g. "`https://appName.azurefd.net/configtab`". + +1. Change the `<>` placeholder in the botId setting to be the `%authorBotId%` value - this is your author Azure AD application's ID from above. This is the same GUID that you entered in the template under "Author Client ID". Please note that there are two places in the manifest (for authors) where you will need to update Bot ID. + +1. Change the `<>` placeholder in the validDomains setting to be the `%appDomain%` value e.g. "`appName.azurefd.net`". + +1. Change the `<>` placeholder in the id setting of the webApplicationInfo section to be the `%authorBotId%` value. Change the `<>` placeholder in the resource setting of the webApplicationInfo section to be the `%appDomain%` value e.g. "`api://appName.azurefd.net`". + +1. Copy the `manifest_authors.json` file to a file named `manifest.json`. + +1. Create a ZIP package with the `manifest.json`,`color.png`, and `outline.png`. The two image files are the icons for your app in Teams. + * Name this package `company-communicator-authors.zip`, so you know that this is the app for the author teams. + * Make sure that the 3 files are the _top level_ of the ZIP package, with no nested folders. + ![image10](images/file-explorer.png) + +1. Delete the `manifest.json` file. + +Repeat the steps above but with the file `Manifest\manifest_users.json` and use `%userBotId%` for `<>` placeholder. Note: you will not need to change anything for the configurationUrl or webApplicationInfo section because the recipients app does not have the configurable tab. Name the resulting package `company-communicator-users.zip`, so you know that this is the app for the recipients. + +## 10. Install the apps in Microsoft Teams + +1. Install the authors app (the `company-communicator-authors.zip` package) to your team of message authors. + * Note that even if non-authors install the app, the UPN list in the app configuration will prevent them from accessing the message authoring experience. Only the users in the sender UPN list will be able to compose and send messages. + * If your tenant has sideloading apps enabled, you can install your app by following the instructions [here](https://docs.microsoft.com/en-us/microsoftteams/platform/concepts/apps/apps-upload#load-your-package-into-teams). + +2. Add the configurable tab to the team of authors, so that they can compose and send messages. + +3. [Upload](https://docs.microsoft.com/en-us/microsoftteams/tenant-apps-catalog-teams) the User app to your tenant's app catalog so that it is available for everyone in your tenant to install. +> **IMPORTANT:** Proactive app installation will work only if you upload the User app to your tenant's app catalog. + +4. Install the User app (the `company-communicator-users.zip` package) to the users and teams that will be the target audience. +> If `proactiveAppInstallation` is enabled, you may skip this step. The service will install the app for all the recipients when authors send a message. + +> **NOTE:** If you are deploying a version of Company Communicator prior to version 4, do NOT use app permission policies to restrict the authors app to the members of the authors team. Microsoft Teams does not support applying different policies to the same bot via two different app packages. + +--- + +# Troubleshooting +Please check the [Troubleshooting](Troubleshooting) guide. diff --git a/Wiki/Deployment-guide-powershell.md b/Wiki/Deployment-guide-powershell.md index dee67e1ea..44ea80abb 100644 --- a/Wiki/Deployment-guide-powershell.md +++ b/Wiki/Deployment-guide-powershell.md @@ -1,4 +1,4 @@ -- [Deployment Guide](#outlook-web-service-ows) +- Deployment Guide **RECOMMENDED** - [Prerequisites](#prerequisites) - [Steps](#Deployment-Steps) - [Deploy to your Azure subscription](#1-deploy-to-your-azure-subscription) @@ -9,7 +9,7 @@ - - - # Prerequisites -To begin, you will need: +To begin, you will need: * An Azure subscription where you can create the following kinds of resources: * App Service @@ -19,6 +19,12 @@ To begin, you will need: * Azure Storage Account * Service Bus * Application Insights + * Azure Key vault +* An role to assign roles in Azure RBAC. To check if you have permission to do this, + * Goto the subscription page in Azure portal. Then, goto Access Control(IAM) and click on `View my access` button. + * Click on your `role` and in search permissions text box, search for `Microsoft.Authorization/roleAssignments/Write`. + * If your current role does not have the permission, then you can grant yourself the built in role `User Access Administrator` or create a custom role. + * Please follow this [link](https://docs.microsoft.com/en-us/azure/role-based-access-control/custom-roles#steps-to-create-a-custom-role) to create a custom role. Use this action `Microsoft.Authorization/roleAssignments/Write` in the custom role to assign roles in Azure RBAC. * A team with the users who will be sending messages with this app. (You can add and remove team members later!) * A copy of the Company Communicator app GitHub repo ([https://github.com/OfficeDev/microsoft-teams-company-communicator-app](https://github.com/OfficeDev/microsoft-teams-company-communicator-app)) @@ -79,6 +85,7 @@ To begin, you will need: - `subscriptionId` - Azure subscription to deploy the solution to (MUST be associated with the Azure AD of the Office 365 tenant that you wish to deploy this solution to.) e.g. 22f602c4-1b8f-46df-8b73-45d7bdfbf58e. - `subscriptionTenantId` - Id of the tenant to deploy to (If you are not sure how to get Tenant ID, please check Azure Active Directory in Azure Portal. Under Manage, click Properties. The tenant ID is shown in the Directory ID box). e.g 98f3ece2-3a5a-428b-aa4f-4c41b3f6eef0. Tenant ID is also available in the `Overview` section". + - `userObjectId` - Object Id of the user to deploy to (If you are not sure how to get Object ID, please check Azure Active Directory in Azure Portal. Under Manage, click Users and select the appropriate user. The Object ID is shown in the Identity section). e.g 98f3ece2-3a5a-428b-aa4f-4c41b3f6eef0. - `resourceGroupName` - Name for a new resource group to deploy the solution to - the script will create this resource group. e.g. CompanyCommunicatorRG. - `region` - Azure region in which to create the resources. The internal name should be used e.g. eastus. Run the following command in Powershell to list internal names. ``` @@ -94,14 +101,37 @@ To begin, you will need: For example, to allow Megan Bowen ([meganb@contoso.com](mailto:meganb@contoso.com)) and Adele Vance ([adelev@contoso.com](mailto:adelev@contoso.com)) to send messages, set this parameter to `meganb@contoso.com;adelev@contoso.com`. You can change this list later by going to the `App Service > Configuration` blade. + - `isUpgrade` - If this is an upgrade for old version of the app template, then value should be true. Otherwise, false is default (First-time deployment). + + - `useCertificate` - If certificate authentication is being used, then value should be true. Otherwise, false is default (Client-secret will be used). + + - `authorAppCertName` - If certificate authentication is being used, then give the name for the new certificate of author bot Azure AD app to be created in Azure Key vault. + + - `userAppCertName` - If certificate authentication is being used, then give the name for the new certificate of user bot Azure AD app to be created in Azure Key vault. + + - `graphAppCertName` - If certificate authentication is being used, then give the name for the new certificate of graph app Azure AD app to be created in Azure Key vault. + - `customDomainOption` - How the app will be hosted on a domain that is not \*.azurewebsites.net. Azure Front Door is an easy option that the template can set up automatically, but it comes with ongoing monthly costs. > **NOTE**: If you plan to use a custom domain name instead of relying on Azure Front Door, read the instructions [here](https://github.com/OfficeDev/microsoft-teams-company-communicator-app/wiki/Custom-domain-option) first. - `proactivelyInstallUserApp`: If proactive app installation should be enabled. Default is true. If enabled, the application will proactively install the User bot for recipients. - `userAppExternalId`: Default value is 148a66bb-e83d-425a-927d-09f4299a9274. This is the external Id provided in the User app manifest. + - `serviceBusWebAppRoleNameGuid`: Default value is `958380b3-630d-4823-b933-f59d92cdcada`. This **MUST** be the same `id` per app deployment. + + > **Note:** Make sure to keep the same values for an upgrade. Please change the role name GUIDs in case of another Company Communicator Deployment in same subscription. + + - `serviceBusPrepFuncRoleNameGuid`: Default value is `ce6ca916-08e9-4639-bfbe-9d098baf42ca`. This **MUST** be the same `id` per app deployment. + - `serviceBusSendFuncRoleNameGuid`: Default value is `960365a2-c7bf-4ff3-8887-efa86fe4a163`. This **MUST** be the same `id` per app deployment. + - `serviceBusDataFuncRoleNameGuid`: Default value is `d42703bc-421d-4d98-bc4d-cd2bb16e5b0a`. This **MUST** be the same `id` per app deployment. + - `storageAccountWebAppRoleNameGuid`: Default value is `edd0cc48-2cf7-490e-99e8-131311e42030`. This **MUST** be the same `id` per app deployment. + - `storageAccountPrepFuncRoleNameGuid`: Default value is `9332a9e9-93f4-48d9-8121-d279f30a732e`. This **MUST** be the same `id` per app deployment. + - `storageAccountDataFuncRoleNameGuid`: Default value is `5b67af51-4a98-47e1-9d22-745069f51a13`. This **MUST** be the same `id` per app deployment. - `defaultCulture`: By default the application uses `en-US` locale. You can choose another locale from the list [here](https://github.com/OfficeDev/microsoft-teams-company-communicator-app/wiki/Localization), if you wish to use the app in different locale. - `hostingPlanSku`: The pricing tier for the hosting plan. Defaul value: Standard. You may choose between Basic, Standard and Premium. - - `hostingPlanSize`: The size of the hosting plan (small - 1, medium - 2, or large - 3). Default value: 1 + - `hostingPlanSize`: The size of the hosting plan (small - 1, medium - 2, or large - 3). Default value: 2 + + > **Note:** The default value is 2 to minimize the chances of an error during app deployment. After deployment you can choose to change the size of the hosting plan. + - `gitRepoUrl` - The URL to the GitHub repository to deploy. Default value: [https://github.com/OfficeDev/microsoft-teams-company-communicator-app.git](https://github.com/OfficeDev/microsoft-teams-company-communicator-app.git) - `gitBranch` - The branch of the GitHub repository to deploy. Default value: master - `appDisplayName` - The app (and bot) display name. Default value:Company Communicator. diff --git a/Wiki/Deployment-guide.md b/Wiki/Deployment-guide.md index 766975d3e..df8991946 100644 --- a/Wiki/Deployment-guide.md +++ b/Wiki/Deployment-guide.md @@ -1,5 +1,5 @@ -- [Deployment Guide](#outlook-web-service-ows) - - [Prerequisites](#prerequisites) +- Deployment Guide + - [Prerequisites](#prerequisites) - [Steps](#Deployment-Steps) - [Register AD Application](#1-register-azure-ad-application) - [Deploy to Azure subscription](#2-deploy-to-your-azure-subscription) @@ -11,6 +11,9 @@ - - - # Prerequisites +The recommendation is to use [Deployment guide using powershell](Deployment-guide-powershell). + + To begin, you will need: * An Azure subscription where you can create the following kinds of resources: * App Service @@ -20,6 +23,12 @@ To begin, you will need: * Azure Storage Account * Service Bus * Application Insights + * Azure Key vault +* An role to assign roles in Azure RBAC. To check if you have permission to do this, + * Goto the subscription page in Azure portal. Then, goto Access Control(IAM) and click on `View my access` button. + * Click on your `role` and in search permissions text box, search for `Microsoft.Authorization/roleAssignments/Write`. + * If your current role does not have the permission, then you can grant yourself the built in role `User Access Administrator` or create a custom role. + * Please follow this [link](https://docs.microsoft.com/en-us/azure/role-based-access-control/custom-roles#steps-to-create-a-custom-role) to create a custom role. Use this action `Microsoft.Authorization/roleAssignments/Write` in the custom role to assign roles in Azure RBAC. * A team with the users who will be sending messages with this app. (You can add or remove team members later!) * A copy of the Company Communicator app GitHub repo (https://github.com/OfficeDev/microsoft-teams-company-communicator-app) @@ -31,12 +40,12 @@ To begin, you will need: ## 1. Register Azure AD application -Register two Azure AD application in your tenant's directory: one for author bot, and another for user bot. +Register three Azure AD application in your tenant's directory: one for author bot, one for user bot and another for graph app. 1. Log in to the Azure Portal for your subscription, and go to the [App registrations](https://portal.azure.com/#blade/Microsoft_AAD_IAM/ActiveDirectoryMenuBlade/RegisteredApps) blade. 1. Click **New registration** to create an Azure AD application. - - **Name**: Name of your Teams App - if you are following the template for a default deployment, we recommend "Company Communicator". + - **Name**: Name of your Teams App - if you are following the template for a default deployment, we recommend "Company Communicator User". - **Supported account types**: Select "Accounts in any organizational directory" (*refer image below*). - Leave the "Redirect URI" field blank for now. @@ -59,13 +68,20 @@ Register two Azure AD application in your tenant's directory: one for author bot - **Supported account types**: Select "Accounts in any organizational directory". - Leave the "Redirect URI" field blank for now. +1. Go back to "App registrations", then repeat steps 2-5 to create another Azure AD application for the Microsoft Graph app. + - **Name**: Name of your Teams App - if you are following the template for a default deployment, we recommend "Company Communicator App". + - **Supported account types**: Select "Accounts in this organizational directory only(Default Directory only - Single tenant)". + - Leave the "Redirect URI" field blank for now. + - At this point you should have the following 5 values: + At this point you should have the following 7 values: 1. Application (client) ID for the user bot. 2. Client secret for the user bot. 3. Directory (tenant) ID. 4. Application (client) Id for the author bot. 5. Client secret for the author bot. + 6. Application (client) Id for the Microsoft Graph App. + 7. Client secret for the Microsoft Graph App. We recommend that you copy the values, we will need them later. @@ -103,10 +119,22 @@ Register two Azure AD application in your tenant's directory: one for author bot 3. **Tenant Id**: The tenant ID. (from Step 1) 4. **Author Client ID**: The application (client) ID of the Microsoft Teams author bot app. (from Step 1) 5. **Author Client Secret**: The client secret of the Microsoft Teams author bot app. (from Step 1) - 6. **Proactively Install User App [Optional]**: Default value is `true`. You may set it to `false` if you want to disable the feature. - 7. **User App ExternalId [Optional]**: Default value is `148a66bb-e83d-425a-927d-09f4299a9274`. This **MUST** be the same `id` that is in the Teams app manifest for the user app. - 8. **DefaultCulture [Optional]**: By default the application uses `en-US` locale. You can choose the locale from the list, if you wish to use the app in different locale.Also, you may add/update the resources for other locales and update this configuration if desired. - 9. **SupportedCultures [Optional]**: This is the list of locales that application supports currently.You may add/update the resources for other locales and update this configuration if desired. + 6. **Microsoft Graph App Client ID**: The application (client) ID of the Microsoft Graph Azure AD app. (from Step 1) + 7. **Microsoft Graph App Secret**: The client secret of the Microsoft Graph Azure AD app. (from Step 1) + 8. **Proactively Install User App [Optional]**: Default value is `true`. You may set it to `false` if you want to disable the feature. + 9. **User App ExternalId [Optional]**: Default value is `148a66bb-e83d-425a-927d-09f4299a9274`. This **MUST** be the same `id` that is in the Teams app manifest for the user app. + 10. **Service Bus Web App Role Name Guid [Optional]**: Default value is `958380b3-630d-4823-b933-f59d92cdcada`. This **MUST** be the same `id` per app deployment. + + > **Note:** Make sure to keep the same values for an upgrade. Please change the role name GUIDs in case of another Company Communicator Deployment in same subscription. + + 11. **Service Bus Prep Func Role Name Guid [Optional]**: Default value is `ce6ca916-08e9-4639-bfbe-9d098baf42ca`. This **MUST** be the same `id` per app deployment. + 12. **Service Bus Send Func Role Name Guid [Optional]**: Default value is `960365a2-c7bf-4ff3-8887-efa86fe4a163`. This **MUST** be the same `id` per app deployment. + 13. **Service Bus Data Func Role Name Guid [Optional]**: Default value is `d42703bc-421d-4d98-bc4d-cd2bb16e5b0a`. This **MUST** be the same `id` per app deployment. + 14. **Storage Account Web App Role Name Guid [Optional]**: Default value is `edd0cc48-2cf7-490e-99e8-131311e42030`. This **MUST** be the same `id` per app deployment. + 15. **Storage Account Prep Func Role Name Guid [Optional]**: Default value is `9332a9e9-93f4-48d9-8121-d279f30a732e`. This **MUST** be the same `id` per app deployment. + 16. **Storage Account Data Func Role Name Guid [Optional]**: Default value is `5b67af51-4a98-47e1-9d22-745069f51a13`. This **MUST** be the same `id` per app deployment. + 17. **DefaultCulture [Optional]**: By default the application uses `en-US` locale. You can choose the locale from the list, if you wish to use the app in different locale.Also, you may add/update the resources for other locales and update this configuration if desired. + 18. **SupportedCultures [Optional]**: This is the list of locales that application supports currently.You may add/update the resources for other locales and update this configuration if desired. > **Note:** Make sure that the values are copied as-is, with no extra spaces. The template checks that GUIDs are exactly 36 characters. @@ -139,7 +167,9 @@ Register two Azure AD application in your tenant's directory: one for author bot > If do not have these values, refer [this section](https://github.com/OfficeDev/microsoft-teams-company-communicator-app/wiki/Troubleshooting#2-forgetting-the-botId-or-appDomain) of the Troubleshooting guide for steps to get these values. -1. Go to **App Registrations** page [here](https://portal.azure.com/#blade/Microsoft_AAD_IAM/ActiveDirectoryMenuBlade/RegisteredApps) and open the author app you created (in Step 1) from the application list. +1. Go to **App Registrations** page [here](https://portal.azure.com/#blade/Microsoft_AAD_IAM/ActiveDirectoryMenuBlade/RegisteredApps) and open the Microsoft Graph Azure AD app you created (in Step 1) from the application list. + + > NOTE: This step is to set-up authentication for Microsoft Graph Azure AD app. 1. Under **Manage**, click on **Authentication** to bring up authentication settings. @@ -193,9 +223,9 @@ Register two Azure AD application in your tenant's directory: one for author bot 2. Click **Save** to commit your changes. -## 4. Add Permissions to your app +## 4. Add Permissions to your Microsoft Graph Azure AD app -Continuing from the Azure AD app registration page where we ended Step 3. +Continuing from the Microsoft Graph Azure AD app registration page where we ended Step 3. 1. Select **API Permissions** blade from the left hand side. @@ -206,11 +236,11 @@ Continuing from the Azure AD app registration page where we ended Step 3. * Under **Commonly used Microsoft APIs**, * Select “Microsoft Graph”, then select **Delegated permissions** and check the following permissions, - 1. **Group.Read.All** + 1. **GroupMember.Read.All** 2. **AppCatalog.Read.All** * then select **Application permissions** and check the following permissions, - 1. **Group.Read.All** + 1. **GroupMember.Read.All** 2. **User.Read.All** 3. **TeamsAppInstallation.ReadWriteForUser.All** @@ -224,7 +254,7 @@ Continuing from the Azure AD app registration page where we ended Step 3. 4. If you are logged in as the Global Administrator, click on the “Grant admin consent for %tenant-name%” button to grant admin consent, else inform your Admin to do the same through the portal.
Alternatively you may follow the steps below: - - Prepare link - https://login.microsoftonline.com/common/adminconsent?client_id=%appId%. Replace the `%appId%` with the `Application (client) ID` of Microsoft Teams author bot app (from above). + - Prepare link - https://login.microsoftonline.com/common/adminconsent?client_id=%appId%. Replace the `%appId%` with the `Application (client) ID` of Microsoft Graph Azure AD app (from above). - Global Administrator can grant consent using the link above. ## 5. Create the Teams app packages diff --git a/Wiki/Home.md b/Wiki/Home.md index d4e46b10c..e816bf371 100644 --- a/Wiki/Home.md +++ b/Wiki/Home.md @@ -15,11 +15,14 @@ It provides a foundation to build custom targeted communication capabilities suc * [Localization](Localization) * Deploying the app * [Deployment guide](Deployment-guide) + * [Deployment guide certificate](Deployment-guide-certificate) * [Deployment guide powershell](Deployment-guide-powershell) * [Troubleshooting](Troubleshooting) * Migrating to newer version + * [v5](v5-migration-guide) * [v4](v4-migration-guide) * [v3](v3-migration-guide) * [v2](v2-migration-guide) +* [Scaling Company Communicator](Scale-app) * [Extending Company Communicator](Taking-it-further) * [Release Notes](Release-notes) \ No newline at end of file diff --git a/Wiki/Release-notes.md b/Wiki/Release-notes.md index c7b2621c1..8ab0a09fc 100644 --- a/Wiki/Release-notes.md +++ b/Wiki/Release-notes.md @@ -6,7 +6,14 @@ Cumulative improvements in Company Communicator App. |Release |Published to
Microsoft Store | |---|---| -| 4.1 | Mar, 2021 +| 5.0 | Nov, 2021 +| 4.1.5 | Sep 29, 2021 +| 4.1.4 | Sep 14, 2021 +| 4.1.3 | Jul 2, 2021 +| 4.1.2 | Jun 25, 2021 +| 4.1.1 | Jun 12, 2021 +| 4.1 | Mar 19, 2021 +| 4.1 | Mar 19, 2021 | 4.0 | Dec 30, 2020 | 3.0 | Oct 29, 2020 | 2.1 | Oct 16, 2020 @@ -16,7 +23,40 @@ Cumulative improvements in Company Communicator App. ### Company Communicator feature release notes -#### 4.1 (Mar, 2021) +#### 5.0 (Nov, 2021) +##### Changes introduced +- Added Key Vault and Managed Identity. +- Support certificate authentication. +- Bug fix to resolve expired delta url. + +#### 4.1.5 (Sep 29, 2021) +##### Changes introduced +- Limit the size of the error and warning messages stored to 1024 characters. + +#### 4.1.4 (Sep 14, 2021) +##### Changes introduced +- Support large number of users. +- Reduce memory usage. + +#### 4.1.3 (Jul 2, 2021) +##### Changes introduced +- Export report for users who have left tenant. + +#### 4.1.2 (Jun 25, 2021) +##### Changes introduced +- Exclude existing guest users with user app installed from receiving message. +- Identify UserType using export report functionality. +- Bug fix preventing proactive installations. + +#### 4.1.1 (Jun 12, 2021) +##### Changes introduced +- Exclude guest users when sending message to: + - Members of one or more Teams. + - Members of one or more Groups. +- Bug fix with the author app interface in dark and high-contrast themes. +- Resolved potential out of memory errors when sending message to large audience. + +#### 4.1 (Mar 19, 2021) ##### Changes introduced - Locale support for multiple languages. - Migration to fluent ui northstar. diff --git a/Wiki/Scale-app.md b/Wiki/Scale-app.md new file mode 100644 index 000000000..fdb6540a2 --- /dev/null +++ b/Wiki/Scale-app.md @@ -0,0 +1,26 @@ +# Scale +If you need to scale the app for large number of users(greater than 200K), please follow the below steps. + +## 1. Create new Storage Account for Durable function. + +1. Find and goto the resource group which is used for the Company Communicator app deployment. +1. Click on **+ Create**. +1. Then, search for **Storage Account** and click on **Create**. +1. Now, fill in the fields such as **Storage account name** and click on **Review + Create**. +1. Once the resource is created, then goto Storage Account. +1. Under **Security + networking**, click on access keys. +1. Then, click on **Show keys** and copy the key1 connection string. +1. Now, goto the Company Communicator prep function and click on **Configuration**. +1. Update the value of **Azure.WebJobsStorage** with the connection string from step 7. +1. Click on **Save** to commit changes. + + > Please make sure to keep the below value less than 50rps, as going over this rate can get the bot blocked. + ``` + "serviceBus": { + "messageHandlerOptions": { + "maxConcurrentCalls": 30 + } + } + ``` + + diff --git a/Wiki/Solution-overview.md b/Wiki/Solution-overview.md index f0a937d6c..2b17c2693 100644 --- a/Wiki/Solution-overview.md +++ b/Wiki/Solution-overview.md @@ -2,12 +2,16 @@ Refer the following image for high level architecture. -![Overview](images/architecture_overview_v2.png) +![Overview](images/architecture_overview_v4.png) The **Company Communicator** app has the following main components: * **App Service**: The app service implements the message compose experience in the team tab, and the messaging endpoint for the bot. * **Service Bus**: The individual messages sent by the bot to the recipients are enqueued on a service bus queue, to be processed by an Azure Function. This queue decouples the message composition experience from the process that delivers the message to recipients. * **Azure Function**: The Azure Functions picks up the messages from the queues, prepares the recipients and delivers them. +* **Azure Key vault**: The Azure Key vault stores the secrets, certificates and connection strings. For more information about the data stored, please check [this](Data-stores.md). +* **Author Bot Registration**: The Author Bot registration is used for author's app. The application is separated from the User application so that different teams policies can be applied. +* **User Bot Registration**: The User Bot registration is used for user's app, which is installed by users to receive messages send by Company Communicator application. +* **Graph App Registration**: The Graph application registration is used for Microsoft Graph api's. The recommended approach is to have a different application registered for managing Microsoft Graph API permissions. * **Microsoft Graph API**: The app leverages Microsoft graph api's to [Search Groups](https://docs.microsoft.com/en-us/graph/api/group-list?view=graph-rest-1.0&tabs=http), [Get Group Transitive Members](https://docs.microsoft.com/en-us/graph/api/group-list-transitivemembers?view=graph-rest-1.0&tabs=http), [Get Users](https://docs.microsoft.com/en-us/graph/api/user-list?view=graph-rest-1.0&tabs=http) and [proactively install the User application for a user](https://docs.microsoft.com/en-us/graph/api/user-add-teamsappinstallation?view=graph-rest-beta&tabs=http). --- @@ -93,7 +97,7 @@ App service requires the following `Delegated permission`: |Sr. No.| Use Case | API| Delegated permissions| API version |--|--|--|--|--| -| 1. | Search Groups | GET [https://graph.microsoft.com/v1.0/groups?$filter=`condition`](https://docs.microsoft.com/en-us/graph/api/group-list?view=graph-rest-1.0&tabs=http) | Group.Read.All| v1.0 +| 1. | Search Groups | GET [https://graph.microsoft.com/v1.0/groups?$filter=`condition`](https://docs.microsoft.com/en-us/graph/api/group-list?view=graph-rest-1.0&tabs=http) | GroupMember.Read.All| v1.0 | 2. | Get App Catalog Id | GET [https://graph.microsoft.com/v1.0/appCatalogs/teamsApps?$filter=distributionMethod eq 'organization'](https://docs.microsoft.com/en-us/graph/api/appcatalogs-list-teamsapps?view=graph-rest-1.0&tabs=http) | AppCatalog.Read.All | v1.0 ### App Permissions @@ -103,7 +107,7 @@ Azure functions require the following `App Permissions` for different use cases: |--|--|--|--|--| | 1. | Get All Users | GET [https://graph.microsoft.com/v1.0/users/delta](https://docs.microsoft.com/en-us/graph/api/user-delta?view=graph-rest-1.0&tabs=http) | User.Read.All | v1.0 | 2. | Get User | GET [https://graph.microsoft.com/v1.0/users/`user-id`](https://docs.microsoft.com/en-us/graph/api/user-get?view=graph-rest-1.0&tabs=http) | User.Read.All| v1.0 -| 3. | Get Group Transitive Members | GET [https://graph.microsoft.com/v1.0/groups/`group-id`/transitiveMembers](https://docs.microsoft.com/en-us/graph/api/group-list-transitivemembers?view=graph-rest-1.0&tabs=http) | Group.Read.All| v1.0 +| 3. | Get Group Transitive Members | GET [https://graph.microsoft.com/v1.0/groups/`group-id`/transitiveMembers](https://docs.microsoft.com/en-us/graph/api/group-list-transitivemembers?view=graph-rest-1.0&tabs=http) | GroupMember.Read.All| v1.0 | 4. | Get Teams App Installation Id | GET [https://graph.microsoft.com/v1.0/users/`user-id`/teamwork/installedApps?$expand=teamsApp&$filter=teamsApp/id eq '`teamsAppId`'](https://docs.microsoft.com/en-us/graph/api/userteamwork-list-installedapps?view=graph-rest-1.0&tabs=http) | TeamsAppInstallation.ReadWriteForUser.All | v1.0 | 5. | Get Chat Id | GET [https://graph.microsoft.com/v1.0/users/`user-id`/teamwork/installedApps/`teamsAppInstallationId`/chat](https://docs.microsoft.com/en-us/graph/api/userscopeteamsappinstallation-get-chat?view=graph-rest-1.0&tabs=http) | TeamsAppInstallation.ReadWriteForUser.All | v1.0 | 6. | Install app for user | POST [https://graph.microsoft.com/v1.0/`user-id`/teamwork/installedApps](https://docs.microsoft.com/en-us/graph/api/userteamwork-post-installedapps?view=graph-rest-1.0&tabs=http) | TeamsAppInstallation.ReadWriteForUser.All | v1.0 \ No newline at end of file diff --git a/Wiki/images/architecture_overview_v4.png b/Wiki/images/architecture_overview_v4.png new file mode 100644 index 000000000..1abad1171 Binary files /dev/null and b/Wiki/images/architecture_overview_v4.png differ diff --git a/Wiki/images/create-certificate.png b/Wiki/images/create-certificate.png new file mode 100644 index 000000000..e96da5528 Binary files /dev/null and b/Wiki/images/create-certificate.png differ diff --git a/Wiki/images/export-cert.png b/Wiki/images/export-cert.png new file mode 100644 index 000000000..1fa241d32 Binary files /dev/null and b/Wiki/images/export-cert.png differ diff --git a/Wiki/images/file-explorer.png b/Wiki/images/file-explorer.png index 137610410..9d656be92 100644 Binary files a/Wiki/images/file-explorer.png and b/Wiki/images/file-explorer.png differ diff --git a/Wiki/images/import-app-service-cert-finished.png b/Wiki/images/import-app-service-cert-finished.png new file mode 100644 index 000000000..1607eb3e3 Binary files /dev/null and b/Wiki/images/import-app-service-cert-finished.png differ diff --git a/Wiki/images/import-key-vault-cert.png b/Wiki/images/import-key-vault-cert.png new file mode 100644 index 000000000..91777ac4c Binary files /dev/null and b/Wiki/images/import-key-vault-cert.png differ diff --git a/Wiki/images/multitenant_app_secret.png b/Wiki/images/multitenant_app_secret.png index 70d08c3b9..6158f1ef9 100644 Binary files a/Wiki/images/multitenant_app_secret.png and b/Wiki/images/multitenant_app_secret.png differ diff --git a/Wiki/images/upload_certificate.png b/Wiki/images/upload_certificate.png new file mode 100644 index 000000000..c7bfa2ffa Binary files /dev/null and b/Wiki/images/upload_certificate.png differ diff --git a/Wiki/v5-migration-guide.md b/Wiki/v5-migration-guide.md new file mode 100644 index 000000000..9404fc8be --- /dev/null +++ b/Wiki/v5-migration-guide.md @@ -0,0 +1,265 @@ +## Company Communicator v5 Migration Guide + +## Upgrading from v4 to v5 +If you have the CCv4 deployed and plan to migrate from CCv4 to CCv5, perform the following steps: + +### 1. Read CCv4 deployment parameters: +Copy all the parameters from the previous deployment (CCv4), and make sure you have the following: + * Name of the Azure subscription. + * Name of the Azure resource group. + * Base resource name. + * Bot tenant ID. + * User bot client ID. + * User bot client secret. + * Author bot client ID. + * Author bot client secret. + * Sender UPN list. + +We will use them in the next steps. + +Please refer [step 2](https://github.com/OfficeDev/microsoft-teams-company-communicator-app/wiki/Deployment-guide) in the Deployment guide for more details about the above values. + +### 2. Register Azure AD application. +1. Register an Azure AD application in your tenant's directory where app is being used. + +2. Log in to the Azure Portal for your subscription, and go to the [App registrations](https://portal.azure.com/#blade/Microsoft_AAD_IAM/ActiveDirectoryMenuBlade/RegisteredApps) blade. + +3. Go to **App Registrations** page [here](https://portal.azure.com/#blade/Microsoft_AAD_IAM/ActiveDirectoryMenuBlade/RegisteredApps) and open the User Bot Azure AD app from the application list. + +4. Under **Manage**, click on **Branding**. + 1. Add ` Users` at the end of existing Name. + + 1. Click **Save** to commit your changes. + +5. Click **New registration** to create an Azure AD application. + - **Name**: Name of your Teams App - if you are following the template for a default deployment, we recommend "Company Communicator App". + - **Supported account types**: Select "Accounts in this organizational directory only(Default Directory only - Single tenant)". + - Leave the "Redirect URI" field blank for now. + + ![Azure AD app registration page](images/multitenant_app_creation.png) + +6. Click **Register** to complete the registration. + +7. When the app is registered, you'll be taken to the app's "Overview" page. Copy the **Application (client) ID**; we will need it later. Verify that the "Supported account types" is set to **Multiple organizations**. + + ![Azure AD app overview page](images/multitenant_app_overview_1.png) + +8. On the side rail in the Manage section, navigate to the "Certificates & secrets" section. In the Client secrets section, click on "+ New client secret". Add a description for the secret, and choose when the secret will expire. Click "Add". + + ![Azure AD app secret](images/multitenant_app_secret.png) + +9. Once the client secret is created, copy its **Value**; we will need it later. + + +### 3. Clean the Company Communicator v4 author app registration + +1. Go to **App Registrations** page [here](https://portal.azure.com/#blade/Microsoft_AAD_IAM/ActiveDirectoryMenuBlade/RegisteredApps) and open the author app you created in Company Communicator v4(in Step 1). + +1. Under **Manage**, click on **Authentication** to bring up authentication settings. + + 1. Delete the entry to **Redirect URIs**. + + 1. Under **Implicit grant**, un-check **ID tokens**. + + 1. Click **Save** to commit your changes. + +1. Back under **Manage**, click on **Expose an API**.This step is to remove the registered domain from current registration so that it can be migrated to graph app registration. Please follow the below steps as per the order mentioned. + + 1. First, delete the list of Authorized client applications. + + 1. Then, click on the scope defined and disable the scope. Click on Save to commit your changes. + + 1. Now, click on the scope defined and then click on Delete. + + 1. Then, to delete the **Application ID URI** there are multiple steps involved. The steps will involve delete and update operation to completely remove the **Application ID URI** from the current Azure AD object Id. + + 1. Delete the **Application ID URI**. + ![Azure AD expose an api page](images/delete_application_uri.png) + 1. Click on the Set **Application ID URI** and then Click on Save. + ![Azure AD expose an api page](images/set_application_uri.png) + 1. Click **Save** to commit your changes. + +1. Back under **Manage**, click on **Manifest**. + + 1. In the editor that appears, find the `optionalClaims` property in the JSON Azure AD application manifest, and replace it with the following block: + + ``` + "optionalClaims": null, + ``` + + 1. Click **Save** to commit your changes. + +1. Select **API Permissions** blade from the left hand side. + + 1. Click on **Group.Read.All** permission and then click on remove permission. + ![Azure AD api permission page](images/remove_permission.png) + + 1. Repeat the same for other permissions. Note: Do not delete the **User.Read** permission. + +### 4. Deploy to your Azure subscription +1. Click on the **Deploy to Azure** button below. + + [![Deploy to Azure](https://azuredeploy.net/deploybutton.png)](https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FOfficeDev%2Fmicrosoft-teams-company-communicator-app%2Fmaster%2FDeployment%2Fazuredeploy.json) + +1. When prompted, log in to your Azure subscription. + > Please use the same subscription being used for your Company Communicator v4 deployment (from step 1). + +1. Azure will create a "Custom deployment" based on the Company Communicator ARM template and ask you to fill in the template parameters. + + > **Note:** Please ensure that you don't use underscore (_) or space in any of the field values otherwise the deployment may fail. + +1. Select a subscription and a resource group. + > Please use the same `subscription`, `resource group` being used for your Company Communicator v4 deployment. (from step 1) + +1. Enter a **Base Resource Name**, which the template uses to generate names for the other resources. + > Please use the same `Base resource name` being used for your Company Communicator v4 deployment. (from step 1) + +1. Update the following fields in the template: + 1. **User Client ID**: The application (client) ID of the Microsoft Teams user bot app. (from Step 1) + 2. **User Client Secret**: The client secret of the Microsoft Teams user bot app. (from Step 1) + 3. **Tenant Id**: The tenant ID. (from Step 1) + 4. **Author Client ID**: The application (client) ID of the Microsoft Teams author bot app. (from Step 1) + 5. **Author Client Secret**: The client secret of the Microsoft Teams author bot app. (from Step 1) + 6. **Microsoft Graph App Client ID**: The application (client) ID of the Microsoft Graph Azure AD app. (from Step 2) + 7. **Microsoft Graph App Secret**: The client secret of the Microsoft Graph Azure AD app. (from Step 2) + 8. **Proactively Install User App [Optional]**: Default value is `true`. You may set it to `false` if you want to disable the feature. + 9. **User App ExternalId [Optional]**: Default value is `148a66bb-e83d-425a-927d-09f4299a9274`. This **MUST** be the same `id` that is in the Teams app manifest for the user app. + 10. **Service Bus Web App Role Name Guid [Optional]**: Default value is `958380b3-630d-4823-b933-f59d92cdcada`. This **MUST** be the same `id` per app deployment. + + > **Note:** Make sure to keep the same values for an upgrade. Please change the role name GUIDs in case of another Company Communicator Deployment in same subscription. + + 11. **Service Bus Prep Func Role Name Guid [Optional]**: Default value is `ce6ca916-08e9-4639-bfbe-9d098baf42ca`. This **MUST** be the same `id` per app deployment. + 12. **Service Bus Send Func Role Name Guid [Optional]**: Default value is `960365a2-c7bf-4ff3-8887-efa86fe4a163`. This **MUST** be the same `id` per app deployment. + 13. **Service Bus Data Func Role Name Guid [Optional]**: Default value is `d42703bc-421d-4d98-bc4d-cd2bb16e5b0a`. This **MUST** be the same `id` per app deployment. + 14. **Storage Account Web App Role Name Guid [Optional]**: Default value is `edd0cc48-2cf7-490e-99e8-131311e42030`. This **MUST** be the same `id` per app deployment. + 15. **Storage Account Prep Func Role Name Guid [Optional]**: Default value is `9332a9e9-93f4-48d9-8121-d279f30a732e`. This **MUST** be the same `id` per app deployment. + 16. **Storage Account Data Func Role Name Guid [Optional]**: Default value is `5b67af51-4a98-47e1-9d22-745069f51a13`. This **MUST** be the same `id` per app deployment. + 17. **DefaultCulture [Optional]**: By default the application uses `en-US` locale. You can choose the locale from the list, if you wish to use the app in different locale.Also, you may add/update the resources for other locales and update this configuration if desired. + 18. **SupportedCultures [Optional]**: This is the list of locales that application supports currently.You may add/update the resources for other locales and update this configuration if desired. + + + > **Note:** Make sure that the values are copied as-is, with no extra spaces. The template checks that GUIDs are exactly 36 characters. + + > **Note:** If your Azure subscription is in a different tenant than the tenant where you want to install the Teams App, please update the `Tenant Id` field with the tenant where you want to install the Teams App. + +1. Update the "Sender UPN List", which is a semicolon-delimited list of users (Authors) who will be allowed to send messages using the Company Communicator. + * For example, to allow Megan Bowen (meganb@contoso.com) and Adele Vance (adelev@contoso.com) to send messages, set this parameter to `meganb@contoso.com;adelev@contoso.com`. + * You can change this list later by going to the App Service's "Configuration" blade. + +1. If you wish to change the app name, description, and icon from the defaults, modify the corresponding template parameters. + +1. Agree to the Azure terms and conditions by clicking on the check box "I agree to the terms and conditions stated above" located at the bottom of the page. + +1. Click on "Purchase" to start the deployment. + +1. Wait for the deployment to finish. You can check the progress of the deployment from the "Notifications" pane of the Azure Portal. It may take **up to an hour** for the deployment to finish. + + > If the deployment fails, see [this section](https://github.com/OfficeDev/microsoft-teams-company-communicator-app/wiki/Troubleshooting#1-code-deployment-failure) of the Troubleshooting guide. + +1. Then go to the "Deployment Center" section of the app service. Click on the "Sync" to update the existing app service to the latest code in the GitHub repository. + + ![Screenshot of refreshing code deployment](images/troubleshooting_sourcecontrols.png) + +1. Please repeat the above step (step 11) for the function apps. + +1. Once the deployment is successfully completed, go to the deployment's "Outputs" tab, and note down the follwing values. We will need them later. + * **authorBotId:** This is the Microsoft Application ID for the Company Communicator app. For the following steps, it will be referred to as `%authorBotId%`. + * **userBotId:** This is the Microsoft Application ID for the Company Communicator app. For the following steps, it will be referred to as `%userBotId%`. + * **appDomain:** This is the base domain for the Company Communicator app. For the following steps, it will be referred to as `%appDomain%`. + +## 5. Set-up Authentication + +1. Note that you have the `%authorBotId%`, `%userBotId%` and `%appDomain%` values from the previous step (Step 2). + + > If do not have these values, refer [this section](https://github.com/OfficeDev/microsoft-teams-company-communicator-app/wiki/Troubleshooting#2-forgetting-the-botId-or-appDomain) of the Troubleshooting guide for steps to get these values. + +1. Go to **App Registrations** page [here](https://portal.azure.com/#blade/Microsoft_AAD_IAM/ActiveDirectoryMenuBlade/RegisteredApps) and open the Microsoft Graph Azure AD app you created (in Step 2) from the application list. + +1. Under **Manage**, click on **Authentication** to bring up authentication settings. + + 1. Add a new entry to **Redirect URIs**: + - **Type**: Web + - **Redirect URI**: Enter `https://%appDomain%/signin-simple-end` for the URL e.g. `https://appName.azurefd.net/signin-simple-end` + + 1. Under **Implicit grant**, check **ID tokens**. + + 1. Click **Save** to commit your changes. + +1. Back under **Manage**, click on **Expose an API**. + + 1. Click on the **Set** link next to **Application ID URI**, and change the value to `api://%appDomain%` e.g. `api://appName.azurefd.net`. + + 1. Click **Save** to commit your changes. + + 1. Click on **Add a scope**, under **Scopes defined by this API**. In the flyout that appears, enter the following values: + * **Scope name:** access_as_user + * **Who can consent?:** Admins and users + * **Admin and user consent display name:** Access the API as the current logged-in user + * **Admin and user consent description:** Access the API as the current logged-in user + + 1. Click **Add scope** to commit your changes. + + 1. Click **Add a client application**, under **Authorized client applications**. In the flyout that appears, enter the following values: + * **Client ID**: `5e3ce6c0-2b1f-4285-8d4b-75ee78787346` + * **Authorized scopes**: Select the scope that ends with `access_as_user`. (There should only be 1 scope in this list.) + + 1. Click **Add application** to commit your changes. + + 1. **Repeat the previous two steps**, but with client ID = `1fec8e78-bce4-4aaf-ab1b-5451cc387264`. After this step you should have **two** client applications (`5e3ce6c0-2b1f-4285-8d4b-75ee78787346` and `1fec8e78-bce4-4aaf-ab1b-5451cc387264`) listed under **Authorized client applications**. + +1. Back under **Manage**, click on **Manifest**. + + 1. In the editor that appears, find the `optionalClaims` property in the JSON Azure AD application manifest, and replace it with the following block: + ``` + "optionalClaims": { + "idToken": [], + "accessToken": [ + { + "name": "upn", + "source": null, + "essential": false, + "additionalProperties": [] + } + ], + "saml2Token": [] + }, + ``` + +1. Click **Save** to commit your changes. + +## 6. Add Permissions to your app + +Continuing from the Azure AD author app registration page where we ended Step 3. + +1. Select **API Permissions** blade from the left hand side. + +2. Click on **Add a permission** button to add permission to your app. + +3. In Microsoft APIs under Select an API label, select the particular service and give the following permissions, + + * Under **Commonly used Microsoft APIs**, + + * Select “Microsoft Graph”, then select **Delegated permissions** and check the following permissions, + 1. **GroupMember.Read.All** + 2. **AppCatalog.Read.All** + + * then select **Application permissions** and check the following permissions, + 1. **GroupMember.Read.All** + 2. **User.Read.All** + 3. **TeamsAppInstallation.ReadWriteForUser.All** + + * Click on **Add Permissions** to commit your changes. + + ![Azure AD API permissions](images/multitenant_app_permissions_1.png) + ![Azure AD API permissions](images/multitenant_app_permissions_2.png) + + > Please refer to [Solution overview](https://github.com/OfficeDev/microsoft-teams-company-communicator-app/wiki/Solution-overview#microsoft-graph-api) for more details about the above permissions. + +4. If you are logged in as the Global Administrator, click on the “Grant admin consent for %tenant-name%” button to grant admin consent, else inform your Admin to do the same through the portal. +
+ Alternatively you may follow the steps below: + - Prepare link - https://login.microsoftonline.com/common/adminconsent?client_id=%appId%. Replace the `%appId%` with the `Application (client) ID` of Microsoft Graph Azure AD app (from above). + - Global Administrator can grant consent using the link above. + +### Migration Status +If you have performed all the steps, migration completes after successful deployment. \ No newline at end of file