From 60dcf93f28d195e628184c3542e54d9721ecd785 Mon Sep 17 00:00:00 2001 From: Loc Mai Date: Fri, 28 May 2021 04:06:56 +0700 Subject: [PATCH 01/10] init token creds with azure authority host --- .../Graph/AzureResourceGraph.cs | 5 ++++- .../Extensions/AzureCloudExtensions.cs | 18 ++++++++++++++++++ src/Promitor.Core/Promitor.Core.csproj | 1 + .../AzureAuthenticationFactory.cs | 10 ++++++---- 4 files changed, 29 insertions(+), 5 deletions(-) diff --git a/src/Promitor.Agents.ResourceDiscovery/Graph/AzureResourceGraph.cs b/src/Promitor.Agents.ResourceDiscovery/Graph/AzureResourceGraph.cs index 589857224..e0f9ed3c0 100644 --- a/src/Promitor.Agents.ResourceDiscovery/Graph/AzureResourceGraph.cs +++ b/src/Promitor.Agents.ResourceDiscovery/Graph/AzureResourceGraph.cs @@ -243,8 +243,11 @@ private async Task OpenConnectionAsync() private async Task CreateClientAsync() { var azureEnvironment = _resourceDeclarationMonitor.CurrentValue.AzureLandscape.Cloud.GetAzureEnvironment(); + var azureAuthoriyHost = _resourceDeclarationMonitor.CurrentValue.AzureLandscape.Cloud.GetAzureAuthorityHost(); - var credentials = await AzureAuthenticationFactory.GetTokenCredentialsAsync(azureEnvironment.ManagementEndpoint, TenantId, _azureAuthenticationInfo); + _logger.LogInformation($"AzureAuthorityHost: {azureAuthoriyHost.ToString()}"); + + var credentials = await AzureAuthenticationFactory.GetTokenCredentialsAsync(azureEnvironment.ManagementEndpoint, TenantId, _azureAuthenticationInfo, azureAuthoriyHost); var resourceGraphClient = new ResourceGraphClient(credentials); var version = Promitor.Core.Version.Get(); diff --git a/src/Promitor.Core/Extensions/AzureCloudExtensions.cs b/src/Promitor.Core/Extensions/AzureCloudExtensions.cs index 6a359c417..32f190aea 100644 --- a/src/Promitor.Core/Extensions/AzureCloudExtensions.cs +++ b/src/Promitor.Core/Extensions/AzureCloudExtensions.cs @@ -1,4 +1,5 @@ using System; +using Azure.Identity; using Microsoft.Azure.Management.ResourceManager.Fluent; using Promitor.Core.Serialization.Enum; @@ -27,5 +28,22 @@ public static AzureEnvironment GetAzureEnvironment(this AzureCloud azureCloud) throw new ArgumentOutOfRangeException(nameof(azureCloud), "No Azure environment is known for"); } } + + public static Uri GetAzureAuthorityHost(this AzureCloud azureCloud) + { + switch (azureCloud) + { + case AzureCloud.Global: + return AzureAuthorityHosts.AzurePublicCloud; + case AzureCloud.China: + return AzureAuthorityHosts.AzureChina; + case AzureCloud.Germany: + return AzureAuthorityHosts.AzureGermany; + case AzureCloud.UsGov: + return AzureAuthorityHosts.AzureGovernment; + default: + throw new ArgumentOutOfRangeException(nameof(azureCloud), "No Azure environment is known for"); + } + } } } \ No newline at end of file diff --git a/src/Promitor.Core/Promitor.Core.csproj b/src/Promitor.Core/Promitor.Core.csproj index 2a40c3831..dd9ab1568 100644 --- a/src/Promitor.Core/Promitor.Core.csproj +++ b/src/Promitor.Core/Promitor.Core.csproj @@ -14,6 +14,7 @@ + diff --git a/src/Promitor.Integrations.Azure/Authentication/AzureAuthenticationFactory.cs b/src/Promitor.Integrations.Azure/Authentication/AzureAuthenticationFactory.cs index 34274e97e..f52d19a65 100644 --- a/src/Promitor.Integrations.Azure/Authentication/AzureAuthenticationFactory.cs +++ b/src/Promitor.Integrations.Azure/Authentication/AzureAuthenticationFactory.cs @@ -69,7 +69,7 @@ public static AzureAuthenticationInfo GetConfiguredAzureAuthentication(IConfigur /// /// Gets a valid token using a Service Principal or a Managed Identity /// - public static async Task GetTokenCredentialsAsync(string resource, string tenantId, AzureAuthenticationInfo authenticationInfo) + public static async Task GetTokenCredentialsAsync(string resource, string tenantId, AzureAuthenticationInfo authenticationInfo, System.Uri azureAuthoriyHost) { Guard.NotNullOrWhitespace(resource, nameof(resource)); Guard.NotNullOrWhitespace(tenantId, nameof(tenantId)); @@ -77,16 +77,18 @@ public static async Task GetTokenCredentialsAsync(string resou TokenCredential tokenCredential; + var tokenCredentialOptions = new TokenCredentialOptions { AuthorityHost = azureAuthoriyHost }; + switch (authenticationInfo.Mode) { case AuthenticationMode.ServicePrincipal: - tokenCredential = new ClientSecretCredential(tenantId, authenticationInfo.IdentityId, authenticationInfo.Secret); + tokenCredential = new ClientSecretCredential(tenantId, authenticationInfo.IdentityId, authenticationInfo.Secret, tokenCredentialOptions); break; case AuthenticationMode.UserAssignedManagedIdentity: - tokenCredential = new ManagedIdentityCredential(authenticationInfo.IdentityId); + tokenCredential = new ManagedIdentityCredential(authenticationInfo.IdentityId, tokenCredentialOptions); break; case AuthenticationMode.SystemAssignedManagedIdentity: - tokenCredential = new ManagedIdentityCredential(); + tokenCredential = new ManagedIdentityCredential( "",tokenCredentialOptions); break; default: tokenCredential = new DefaultAzureCredential(); From dd2c867865144bd77676db71f049248d176343a6 Mon Sep 17 00:00:00 2001 From: Loc Mai Date: Fri, 28 May 2021 11:21:48 +0700 Subject: [PATCH 02/10] pass the ResourceManagerEndpoint to the client --- .../Graph/AzureResourceGraph.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/Promitor.Agents.ResourceDiscovery/Graph/AzureResourceGraph.cs b/src/Promitor.Agents.ResourceDiscovery/Graph/AzureResourceGraph.cs index e0f9ed3c0..e21dfeb4e 100644 --- a/src/Promitor.Agents.ResourceDiscovery/Graph/AzureResourceGraph.cs +++ b/src/Promitor.Agents.ResourceDiscovery/Graph/AzureResourceGraph.cs @@ -245,10 +245,11 @@ private async Task CreateClientAsync() var azureEnvironment = _resourceDeclarationMonitor.CurrentValue.AzureLandscape.Cloud.GetAzureEnvironment(); var azureAuthoriyHost = _resourceDeclarationMonitor.CurrentValue.AzureLandscape.Cloud.GetAzureAuthorityHost(); - _logger.LogInformation($"AzureAuthorityHost: {azureAuthoriyHost.ToString()}"); - var credentials = await AzureAuthenticationFactory.GetTokenCredentialsAsync(azureEnvironment.ManagementEndpoint, TenantId, _azureAuthenticationInfo, azureAuthoriyHost); - var resourceGraphClient = new ResourceGraphClient(credentials); + + var baseUri = new System.Uri(azureEnvironment.ResourceManagerEndpoint); + + var resourceGraphClient = new ResourceGraphClient(baseUri ,credentials); var version = Promitor.Core.Version.Get(); var promitorUserAgent = UserAgent.Generate("Resource-Discovery", version); From 80595522ee41b5dac76c67a9e054e284034fa1c1 Mon Sep 17 00:00:00 2001 From: Loc Mai Date: Fri, 28 May 2021 11:32:31 +0700 Subject: [PATCH 03/10] fix code quality: redundant qualifier --- .../Graph/AzureResourceGraph.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Promitor.Agents.ResourceDiscovery/Graph/AzureResourceGraph.cs b/src/Promitor.Agents.ResourceDiscovery/Graph/AzureResourceGraph.cs index e21dfeb4e..f245dfeef 100644 --- a/src/Promitor.Agents.ResourceDiscovery/Graph/AzureResourceGraph.cs +++ b/src/Promitor.Agents.ResourceDiscovery/Graph/AzureResourceGraph.cs @@ -247,7 +247,7 @@ private async Task CreateClientAsync() var credentials = await AzureAuthenticationFactory.GetTokenCredentialsAsync(azureEnvironment.ManagementEndpoint, TenantId, _azureAuthenticationInfo, azureAuthoriyHost); - var baseUri = new System.Uri(azureEnvironment.ResourceManagerEndpoint); + var baseUri = new Uri(azureEnvironment.ResourceManagerEndpoint); var resourceGraphClient = new ResourceGraphClient(baseUri ,credentials); From e3a67d009c7525886458769f5d959f87061366b1 Mon Sep 17 00:00:00 2001 From: Loc Mai Date: Fri, 28 May 2021 12:00:52 +0700 Subject: [PATCH 04/10] fix spelling --- .../Graph/AzureResourceGraph.cs | 4 ++-- .../Authentication/AzureAuthenticationFactory.cs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Promitor.Agents.ResourceDiscovery/Graph/AzureResourceGraph.cs b/src/Promitor.Agents.ResourceDiscovery/Graph/AzureResourceGraph.cs index f245dfeef..d580ada11 100644 --- a/src/Promitor.Agents.ResourceDiscovery/Graph/AzureResourceGraph.cs +++ b/src/Promitor.Agents.ResourceDiscovery/Graph/AzureResourceGraph.cs @@ -243,9 +243,9 @@ private async Task OpenConnectionAsync() private async Task CreateClientAsync() { var azureEnvironment = _resourceDeclarationMonitor.CurrentValue.AzureLandscape.Cloud.GetAzureEnvironment(); - var azureAuthoriyHost = _resourceDeclarationMonitor.CurrentValue.AzureLandscape.Cloud.GetAzureAuthorityHost(); + var azureAuthorityHost = _resourceDeclarationMonitor.CurrentValue.AzureLandscape.Cloud.GetAzureAuthorityHost(); - var credentials = await AzureAuthenticationFactory.GetTokenCredentialsAsync(azureEnvironment.ManagementEndpoint, TenantId, _azureAuthenticationInfo, azureAuthoriyHost); + var credentials = await AzureAuthenticationFactory.GetTokenCredentialsAsync(azureEnvironment.ManagementEndpoint, TenantId, _azureAuthenticationInfo, azureAuthorityHost); var baseUri = new Uri(azureEnvironment.ResourceManagerEndpoint); diff --git a/src/Promitor.Integrations.Azure/Authentication/AzureAuthenticationFactory.cs b/src/Promitor.Integrations.Azure/Authentication/AzureAuthenticationFactory.cs index f52d19a65..c40bf3db2 100644 --- a/src/Promitor.Integrations.Azure/Authentication/AzureAuthenticationFactory.cs +++ b/src/Promitor.Integrations.Azure/Authentication/AzureAuthenticationFactory.cs @@ -69,7 +69,7 @@ public static AzureAuthenticationInfo GetConfiguredAzureAuthentication(IConfigur /// /// Gets a valid token using a Service Principal or a Managed Identity /// - public static async Task GetTokenCredentialsAsync(string resource, string tenantId, AzureAuthenticationInfo authenticationInfo, System.Uri azureAuthoriyHost) + public static async Task GetTokenCredentialsAsync(string resource, string tenantId, AzureAuthenticationInfo authenticationInfo, System.Uri azureAuthorityHost) { Guard.NotNullOrWhitespace(resource, nameof(resource)); Guard.NotNullOrWhitespace(tenantId, nameof(tenantId)); @@ -77,7 +77,7 @@ public static async Task GetTokenCredentialsAsync(string resou TokenCredential tokenCredential; - var tokenCredentialOptions = new TokenCredentialOptions { AuthorityHost = azureAuthoriyHost }; + var tokenCredentialOptions = new TokenCredentialOptions { AuthorityHost = azureAuthorityHost }; switch (authenticationInfo.Mode) { From 26473fabfb7549253c2c8cc7057fb86b81faf851 Mon Sep 17 00:00:00 2001 From: Loc Mai Date: Fri, 28 May 2021 12:37:37 +0700 Subject: [PATCH 05/10] remove empty param --- .../Authentication/AzureAuthenticationFactory.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Promitor.Integrations.Azure/Authentication/AzureAuthenticationFactory.cs b/src/Promitor.Integrations.Azure/Authentication/AzureAuthenticationFactory.cs index c40bf3db2..d7a814611 100644 --- a/src/Promitor.Integrations.Azure/Authentication/AzureAuthenticationFactory.cs +++ b/src/Promitor.Integrations.Azure/Authentication/AzureAuthenticationFactory.cs @@ -88,7 +88,7 @@ public static async Task GetTokenCredentialsAsync(string resou tokenCredential = new ManagedIdentityCredential(authenticationInfo.IdentityId, tokenCredentialOptions); break; case AuthenticationMode.SystemAssignedManagedIdentity: - tokenCredential = new ManagedIdentityCredential( "",tokenCredentialOptions); + tokenCredential = new ManagedIdentityCredential(options:tokenCredentialOptions); break; default: tokenCredential = new DefaultAzureCredential(); From af89e7f242ee58430770f02f7af8fd76fb92ce0b Mon Sep 17 00:00:00 2001 From: Loc Mai Date: Fri, 28 May 2021 12:40:13 +0700 Subject: [PATCH 06/10] fix nit --- .../Graph/AzureResourceGraph.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/Promitor.Agents.ResourceDiscovery/Graph/AzureResourceGraph.cs b/src/Promitor.Agents.ResourceDiscovery/Graph/AzureResourceGraph.cs index d580ada11..60adf24e6 100644 --- a/src/Promitor.Agents.ResourceDiscovery/Graph/AzureResourceGraph.cs +++ b/src/Promitor.Agents.ResourceDiscovery/Graph/AzureResourceGraph.cs @@ -246,10 +246,9 @@ private async Task CreateClientAsync() var azureAuthorityHost = _resourceDeclarationMonitor.CurrentValue.AzureLandscape.Cloud.GetAzureAuthorityHost(); var credentials = await AzureAuthenticationFactory.GetTokenCredentialsAsync(azureEnvironment.ManagementEndpoint, TenantId, _azureAuthenticationInfo, azureAuthorityHost); + var resourceManagerBaseUri = new Uri(azureEnvironment.ResourceManagerEndpoint); - var baseUri = new Uri(azureEnvironment.ResourceManagerEndpoint); - - var resourceGraphClient = new ResourceGraphClient(baseUri ,credentials); + var resourceGraphClient = new ResourceGraphClient(resourceManagerBaseUri, credentials); var version = Promitor.Core.Version.Get(); var promitorUserAgent = UserAgent.Generate("Resource-Discovery", version); From bbd1f400730eb9bbcdbc39307aef2a4c13584c42 Mon Sep 17 00:00:00 2001 From: Loc Mai Date: Fri, 28 May 2021 16:31:28 +0700 Subject: [PATCH 07/10] add unit test for GetAzureAuthorityHost --- .../Azure/AzureCloudUnitTests.cs | 67 +++++++++++++++++++ 1 file changed, 67 insertions(+) diff --git a/src/Promitor.Tests.Unit/Azure/AzureCloudUnitTests.cs b/src/Promitor.Tests.Unit/Azure/AzureCloudUnitTests.cs index 479b074a7..16fea2af3 100644 --- a/src/Promitor.Tests.Unit/Azure/AzureCloudUnitTests.cs +++ b/src/Promitor.Tests.Unit/Azure/AzureCloudUnitTests.cs @@ -1,5 +1,6 @@ using System; using System.ComponentModel; +using Azure.Identity; using Microsoft.Azure.Management.ResourceManager.Fluent; using Promitor.Core.Extensions; using Promitor.Core.Serialization.Enum; @@ -75,5 +76,71 @@ public void GetAzureEnvironment_ForUnspecifiedAzureCloud_ThrowsException() // Act & Assert Assert.Throws(()=> azureCloud.GetAzureEnvironment()); } + + [Fact] + public void GetAzureAuthorityHost_ForAzureGlobalCloud_ProvidesCorrectEnvironmentInfo() + { + // Arrange + var azureCloud = AzureCloud.Global; + var expectedAuthorityHost = AzureAuthorityHosts.AzurePublicCloud; + + // Act + var actualAuthorityHost = azureCloud.GetAzureAuthorityHost(); + + // Assert + PromitorAssert.Equal(expectedAuthorityHost, actualAuthorityHost); + } + + [Fact] + public void GetAzureAuthorityHost_ForAzureChinaCloud_ProvidesCorrectEnvironmentInfo() + { + // Arrange + var azureCloud = AzureCloud.China; + var expectedAuthorityHost = AzureAuthorityHosts.AzureChina; + + // Act + var actualAuthorityHost = azureCloud.GetAzureAuthorityHost(); + + // Assert + PromitorAssert.Equal(expectedAuthorityHost, actualAuthorityHost); + } + + [Fact] + public void GetAzureAuthorityHost_ForAzureGermanCloud_ProvidesCorrectEnvironmentInfo() + { + // Arrange + var azureCloud = AzureCloud.Germany; + var expectedAuthorityHost = AzureAuthorityHosts.AzureGermany; + + // Act + var actualAuthorityHost = azureCloud.GetAzureAuthorityHost(); + + // Assert + PromitorAssert.Equal(expectedAuthorityHost, actualAuthorityHost); + } + + [Fact] + public void GetAzureAuthorityHost_ForAzureUSGovernmentCloud_ProvidesCorrectEnvironmentInfo() + { + // Arrange + var azureCloud = AzureCloud.UsGov; + var expectedEnvironment = AzureAuthorityHosts.AzureGovernment; + + // Act + var actualAuthorityHost = azureCloud.GetAzureAuthorityHost(); + + // Assert + PromitorAssert.Equal(expectedAuthorityHost, actualAuthorityHost); + } + + [Fact] + public void GetAzureAuthorityHost_ForUnspecifiedAzureCloud_ThrowsException() + { + // Arrange + var azureCloud = AzureCloud.Unspecified; + + // Act & Assert + Assert.Throws(() => azureCloud.GetAzureAuthorityHost()); + } } } From 54383432405e9b84714a8ccdd6d6baac2b1f8c8c Mon Sep 17 00:00:00 2001 From: Loc Mai Date: Fri, 28 May 2021 16:38:28 +0700 Subject: [PATCH 08/10] fix copy pasta --- src/Promitor.Tests.Unit/Azure/AzureCloudUnitTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Promitor.Tests.Unit/Azure/AzureCloudUnitTests.cs b/src/Promitor.Tests.Unit/Azure/AzureCloudUnitTests.cs index 16fea2af3..941dd4c83 100644 --- a/src/Promitor.Tests.Unit/Azure/AzureCloudUnitTests.cs +++ b/src/Promitor.Tests.Unit/Azure/AzureCloudUnitTests.cs @@ -124,7 +124,7 @@ public void GetAzureAuthorityHost_ForAzureUSGovernmentCloud_ProvidesCorrectEnvir { // Arrange var azureCloud = AzureCloud.UsGov; - var expectedEnvironment = AzureAuthorityHosts.AzureGovernment; + var expectedAuthorityHost = AzureAuthorityHosts.AzureGovernment; // Act var actualAuthorityHost = azureCloud.GetAzureAuthorityHost(); From b3f0554c8db2b0389b869e12a99815b908507837 Mon Sep 17 00:00:00 2001 From: Loc Mai Date: Fri, 28 May 2021 16:41:46 +0700 Subject: [PATCH 09/10] fix copy pasta --- src/Promitor.Tests.Unit/Azure/AzureCloudUnitTests.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Promitor.Tests.Unit/Azure/AzureCloudUnitTests.cs b/src/Promitor.Tests.Unit/Azure/AzureCloudUnitTests.cs index 941dd4c83..1c961c53b 100644 --- a/src/Promitor.Tests.Unit/Azure/AzureCloudUnitTests.cs +++ b/src/Promitor.Tests.Unit/Azure/AzureCloudUnitTests.cs @@ -78,7 +78,7 @@ public void GetAzureEnvironment_ForUnspecifiedAzureCloud_ThrowsException() } [Fact] - public void GetAzureAuthorityHost_ForAzureGlobalCloud_ProvidesCorrectEnvironmentInfo() + public void GetAzureAuthorityHost_ForAzureGlobalCloud_ProvidesCorrectAuthorityHost() { // Arrange var azureCloud = AzureCloud.Global; @@ -92,7 +92,7 @@ public void GetAzureAuthorityHost_ForAzureGlobalCloud_ProvidesCorrectEnvironment } [Fact] - public void GetAzureAuthorityHost_ForAzureChinaCloud_ProvidesCorrectEnvironmentInfo() + public void GetAzureAuthorityHost_ForAzureChinaCloud_ProvidesCorrectAuthorityHost() { // Arrange var azureCloud = AzureCloud.China; @@ -106,7 +106,7 @@ public void GetAzureAuthorityHost_ForAzureChinaCloud_ProvidesCorrectEnvironmentI } [Fact] - public void GetAzureAuthorityHost_ForAzureGermanCloud_ProvidesCorrectEnvironmentInfo() + public void GetAzureAuthorityHost_ForAzureGermanCloud_ProvidesCorrectAuthorityHost() { // Arrange var azureCloud = AzureCloud.Germany; @@ -120,7 +120,7 @@ public void GetAzureAuthorityHost_ForAzureGermanCloud_ProvidesCorrectEnvironment } [Fact] - public void GetAzureAuthorityHost_ForAzureUSGovernmentCloud_ProvidesCorrectEnvironmentInfo() + public void GetAzureAuthorityHost_ForAzureUSGovernmentCloud_ProvidesCorrectAuthorityHost() { // Arrange var azureCloud = AzureCloud.UsGov; From 2715a3acda054f37b1435038f9c3ee97a358e9f6 Mon Sep 17 00:00:00 2001 From: Loc Mai Date: Fri, 28 May 2021 17:07:20 +0700 Subject: [PATCH 10/10] fix code quality: assert --- src/Promitor.Tests.Unit/Azure/AzureCloudUnitTests.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Promitor.Tests.Unit/Azure/AzureCloudUnitTests.cs b/src/Promitor.Tests.Unit/Azure/AzureCloudUnitTests.cs index 1c961c53b..abcc83beb 100644 --- a/src/Promitor.Tests.Unit/Azure/AzureCloudUnitTests.cs +++ b/src/Promitor.Tests.Unit/Azure/AzureCloudUnitTests.cs @@ -88,7 +88,7 @@ public void GetAzureAuthorityHost_ForAzureGlobalCloud_ProvidesCorrectAuthorityHo var actualAuthorityHost = azureCloud.GetAzureAuthorityHost(); // Assert - PromitorAssert.Equal(expectedAuthorityHost, actualAuthorityHost); + Assert.True(expectedAuthorityHost.Equals(actualAuthorityHost)); } [Fact] @@ -102,7 +102,7 @@ public void GetAzureAuthorityHost_ForAzureChinaCloud_ProvidesCorrectAuthorityHos var actualAuthorityHost = azureCloud.GetAzureAuthorityHost(); // Assert - PromitorAssert.Equal(expectedAuthorityHost, actualAuthorityHost); + Assert.True(expectedAuthorityHost.Equals(actualAuthorityHost)); } [Fact] @@ -116,7 +116,7 @@ public void GetAzureAuthorityHost_ForAzureGermanCloud_ProvidesCorrectAuthorityHo var actualAuthorityHost = azureCloud.GetAzureAuthorityHost(); // Assert - PromitorAssert.Equal(expectedAuthorityHost, actualAuthorityHost); + Assert.True(expectedAuthorityHost.Equals(actualAuthorityHost)); } [Fact] @@ -130,7 +130,7 @@ public void GetAzureAuthorityHost_ForAzureUSGovernmentCloud_ProvidesCorrectAutho var actualAuthorityHost = azureCloud.GetAzureAuthorityHost(); // Assert - PromitorAssert.Equal(expectedAuthorityHost, actualAuthorityHost); + Assert.True(expectedAuthorityHost.Equals(actualAuthorityHost)); } [Fact]