From 6d962f91897c0c5b3e1b095b53cf2fef7ed82829 Mon Sep 17 00:00:00 2001 From: Gajibilli Koteswara Rao Date: Tue, 1 Feb 2022 23:04:17 +0530 Subject: [PATCH 01/26] Code changes for Blob, Queue, Servicebus and EventHub of New SDK version V3 --- .../ConnectionStringValidationController.cs | 23 +- .../DiagnosticsExtension.csproj | 173 ++++++++++++++- .../BlobStorageValidator.cs | 192 ++++++++++++++++ .../ConnectionStringType.cs | 9 +- .../ConnectionStringValidationResult.cs | 16 +- .../EventHubsValidator.cs | 163 +++++++++++++- .../Exceptions/ManagedIdentityException.cs | 29 +++ .../FileShareStorageValidator.cs | 207 ++++++++++++++++++ .../HttpValidator.cs | 4 + .../IConnectionStringValidator.cs | 2 +- .../KeyVaultValidator.cs | 4 + .../MySqlValidator.cs | 4 + .../QueueStorageValidator.cs | 199 +++++++++++++++++ .../ServiceBusValidator.cs | 176 ++++++++++++++- .../SqlServerValidator.cs | 4 + .../StorageValidator.cs | 4 + DiagnosticsExtension/Web.config | 72 +++++- DiagnosticsExtension/packages.config | 62 +++++- 18 files changed, 1294 insertions(+), 49 deletions(-) create mode 100644 DiagnosticsExtension/Models/ConnectionStringValidator/BlobStorageValidator.cs create mode 100644 DiagnosticsExtension/Models/ConnectionStringValidator/Exceptions/ManagedIdentityException.cs create mode 100644 DiagnosticsExtension/Models/ConnectionStringValidator/FileShareStorageValidator.cs create mode 100644 DiagnosticsExtension/Models/ConnectionStringValidator/QueueStorageValidator.cs diff --git a/DiagnosticsExtension/Controllers/ConnectionStringValidationController.cs b/DiagnosticsExtension/Controllers/ConnectionStringValidationController.cs index 29623e8c..990b2a19 100644 --- a/DiagnosticsExtension/Controllers/ConnectionStringValidationController.cs +++ b/DiagnosticsExtension/Controllers/ConnectionStringValidationController.cs @@ -1,4 +1,4 @@ -// ----------------------------------------------------------------------- +// ----------------------------------------------------------------------- // // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. See LICENSE in the project root for license information. @@ -36,7 +36,9 @@ public ConnectionStringValidationController() new SqlServerValidator(), new MySqlValidator(), new KeyVaultValidator(), - new StorageValidator(), + new BlobStorageValidator(), + new QueueStorageValidator(), + new FileShareStorageValidator(), new ServiceBusValidator(), new EventHubsValidator(), new HttpValidator() @@ -79,18 +81,21 @@ public async Task Validate([FromBody] ConnectionStringReque [HttpGet] [Route("validateappsetting")] - public async Task ValidateAppSetting(string appSettingName, string type) + public async Task ValidateAppSetting(string appSettingName, string type, string entityName = null) { - var envDict = Environment.GetEnvironmentVariables(); - if (envDict.Contains(appSettingName)) + + bool success = Enum.TryParse(type, out ConnectionStringType csType); + if (success && typeValidatorMap.ContainsKey(csType)) { - var connectionString = (string)envDict[appSettingName]; - return await Validate(connectionString, type); + var result = await typeValidatorMap[csType].ValidateViaAppsettingAsync(appSettingName, entityName); + return Request.CreateResponse(HttpStatusCode.OK, result); } else { - return Request.CreateErrorResponse(HttpStatusCode.NotFound, $"AppSetting {appSettingName} not found"); + return Request.CreateErrorResponse(HttpStatusCode.BadRequest, $"Type '{type}' is not supported"); } + } + } -} \ No newline at end of file +} diff --git a/DiagnosticsExtension/DiagnosticsExtension.csproj b/DiagnosticsExtension/DiagnosticsExtension.csproj index fff1a670..ef5739ce 100644 --- a/DiagnosticsExtension/DiagnosticsExtension.csproj +++ b/DiagnosticsExtension/DiagnosticsExtension.csproj @@ -56,6 +56,36 @@ ..\packages\Antlr.3.5.0.2\lib\Antlr3.Runtime.dll + + ..\packages\Azure.Core.1.21.0\lib\net461\Azure.Core.dll + + + ..\packages\Azure.Core.Amqp.1.2.0\lib\netstandard2.0\Azure.Core.Amqp.dll + + + ..\packages\Azure.Identity.1.4.0\lib\netstandard2.0\Azure.Identity.dll + + + ..\packages\Azure.Messaging.EventHubs.5.6.2\lib\netstandard2.0\Azure.Messaging.EventHubs.dll + + + ..\packages\Azure.Messaging.EventHubs.Processor.5.6.2\lib\netstandard2.0\Azure.Messaging.EventHubs.Processor.dll + + + ..\packages\Azure.Messaging.ServiceBus.7.5.1\lib\netstandard2.0\Azure.Messaging.ServiceBus.dll + + + ..\packages\Azure.Storage.Blobs.12.8.0\lib\netstandard2.0\Azure.Storage.Blobs.dll + + + ..\packages\Azure.Storage.Common.12.9.0\lib\netstandard2.0\Azure.Storage.Common.dll + + + ..\packages\Azure.Storage.Files.Shares.12.8.0\lib\netstandard2.0\Azure.Storage.Files.Shares.dll + + + ..\packages\Azure.Storage.Queues.12.8.0\lib\netstandard2.0\Azure.Storage.Queues.dll + ..\packages\EntityFramework.6.2.0\lib\net45\EntityFramework.dll @@ -63,7 +93,7 @@ ..\packages\EntityFramework.6.2.0\lib\net45\EntityFramework.SqlServer.dll - ..\packages\Microsoft.Azure.Amqp.2.4.9\lib\net45\Microsoft.Azure.Amqp.dll + ..\packages\Microsoft.Azure.Amqp.2.5.6\lib\net45\Microsoft.Azure.Amqp.dll ..\packages\Microsoft.Azure.EventHubs.3.0.0\lib\net461\Microsoft.Azure.EventHubs.dll @@ -80,6 +110,24 @@ ..\packages\Microsoft.Azure.Services.AppAuthentication.1.0.3\lib\net452\Microsoft.Azure.Services.AppAuthentication.dll + + ..\packages\Microsoft.Azure.Storage.Blob.11.2.3\lib\net452\Microsoft.Azure.Storage.Blob.dll + + + ..\packages\Microsoft.Azure.Storage.Common.11.2.3\lib\net452\Microsoft.Azure.Storage.Common.dll + + + ..\packages\Microsoft.Azure.WebJobs.Core.3.0.30\lib\netstandard2.0\Microsoft.Azure.WebJobs.dll + + + ..\packages\Microsoft.Azure.WebJobs.Extensions.ServiceBus.5.2.0\lib\netstandard2.0\Microsoft.Azure.WebJobs.Extensions.ServiceBus.dll + + + ..\packages\Microsoft.Azure.WebJobs.3.0.30\lib\netstandard2.0\Microsoft.Azure.WebJobs.Host.dll + + + ..\packages\Microsoft.Bcl.AsyncInterfaces.1.0.0\lib\net461\Microsoft.Bcl.AsyncInterfaces.dll + ..\packages\Microsoft.Data.Edm.5.8.4\lib\net40\Microsoft.Data.Edm.dll @@ -90,6 +138,72 @@ ..\packages\Microsoft.Data.Services.Client.5.8.4\lib\net40\Microsoft.Data.Services.Client.dll + + ..\packages\Microsoft.Extensions.Azure.1.1.1\lib\netstandard2.0\Microsoft.Extensions.Azure.dll + + + ..\packages\Microsoft.Extensions.Configuration.2.1.1\lib\netstandard2.0\Microsoft.Extensions.Configuration.dll + + + ..\packages\Microsoft.Extensions.Configuration.Abstractions.2.1.1\lib\netstandard2.0\Microsoft.Extensions.Configuration.Abstractions.dll + + + ..\packages\Microsoft.Extensions.Configuration.Binder.2.1.1\lib\netstandard2.0\Microsoft.Extensions.Configuration.Binder.dll + + + ..\packages\Microsoft.Extensions.Configuration.EnvironmentVariables.2.1.0\lib\netstandard2.0\Microsoft.Extensions.Configuration.EnvironmentVariables.dll + + + ..\packages\Microsoft.Extensions.Configuration.FileExtensions.2.1.0\lib\netstandard2.0\Microsoft.Extensions.Configuration.FileExtensions.dll + + + ..\packages\Microsoft.Extensions.Configuration.Json.2.1.0\lib\netstandard2.0\Microsoft.Extensions.Configuration.Json.dll + + + ..\packages\Microsoft.Extensions.DependencyInjection.2.1.0\lib\net461\Microsoft.Extensions.DependencyInjection.dll + + + ..\packages\Microsoft.Extensions.DependencyInjection.Abstractions.2.1.1\lib\netstandard2.0\Microsoft.Extensions.DependencyInjection.Abstractions.dll + + + ..\packages\Microsoft.Extensions.FileProviders.Abstractions.2.1.0\lib\netstandard2.0\Microsoft.Extensions.FileProviders.Abstractions.dll + + + ..\packages\Microsoft.Extensions.FileProviders.Physical.2.1.0\lib\netstandard2.0\Microsoft.Extensions.FileProviders.Physical.dll + + + ..\packages\Microsoft.Extensions.FileSystemGlobbing.2.1.0\lib\netstandard2.0\Microsoft.Extensions.FileSystemGlobbing.dll + + + ..\packages\Microsoft.Extensions.Hosting.2.1.0\lib\netstandard2.0\Microsoft.Extensions.Hosting.dll + + + ..\packages\Microsoft.Extensions.Hosting.Abstractions.2.1.0\lib\netstandard2.0\Microsoft.Extensions.Hosting.Abstractions.dll + + + ..\packages\Microsoft.Extensions.Logging.2.1.1\lib\netstandard2.0\Microsoft.Extensions.Logging.dll + + + ..\packages\Microsoft.Extensions.Logging.Abstractions.2.1.1\lib\netstandard2.0\Microsoft.Extensions.Logging.Abstractions.dll + + + ..\packages\Microsoft.Extensions.Logging.Configuration.2.1.0\lib\netstandard2.0\Microsoft.Extensions.Logging.Configuration.dll + + + ..\packages\Microsoft.Extensions.Options.2.1.1\lib\netstandard2.0\Microsoft.Extensions.Options.dll + + + ..\packages\Microsoft.Extensions.Options.ConfigurationExtensions.2.1.0\lib\netstandard2.0\Microsoft.Extensions.Options.ConfigurationExtensions.dll + + + ..\packages\Microsoft.Extensions.Primitives.2.1.1\lib\netstandard2.0\Microsoft.Extensions.Primitives.dll + + + ..\packages\Microsoft.Identity.Client.4.30.1\lib\net461\Microsoft.Identity.Client.dll + + + ..\packages\Microsoft.Identity.Client.Extensions.Msal.2.18.4\lib\net45\Microsoft.Identity.Client.Extensions.Msal.dll + ..\packages\Microsoft.IdentityModel.Clients.ActiveDirectory.4.5.0\lib\net45\Microsoft.IdentityModel.Clients.ActiveDirectory.dll @@ -128,6 +242,12 @@ ..\packages\Swashbuckle.Core.5.6.0\lib\net40\Swashbuckle.Core.dll + + ..\packages\System.Buffers.4.5.1\lib\net461\System.Buffers.dll + + + ..\packages\System.ComponentModel.Annotations.4.4.0\lib\net461\System.ComponentModel.Annotations.dll + @@ -135,8 +255,13 @@ ..\packages\System.Data.SqlClient.4.8.2\lib\net461\System.Data.SqlClient.dll - - ..\packages\System.Diagnostics.DiagnosticSource.4.5.1\lib\net46\System.Diagnostics.DiagnosticSource.dll + + ..\packages\System.Diagnostics.DiagnosticSource.4.6.0\lib\net46\System.Diagnostics.DiagnosticSource.dll + + + ..\packages\System.Diagnostics.TraceSource.4.3.0\lib\net46\System.Diagnostics.TraceSource.dll + True + True @@ -148,6 +273,12 @@ True + + ..\packages\System.Memory.4.5.4\lib\net461\System.Memory.dll + + + ..\packages\System.Memory.Data.1.0.2\lib\net461\System.Memory.Data.dll + ..\packages\System.Net.Http.4.3.3\lib\net46\System.Net.Http.dll True @@ -169,21 +300,26 @@ ..\packages\System.Net.WebSockets.Client.4.0.2\lib\net46\System.Net.WebSockets.Client.dll True + + + ..\packages\System.Numerics.Vectors.4.5.0\lib\net46\System.Numerics.Vectors.dll + - ..\packages\System.Reflection.TypeExtensions.4.5.0\lib\net461\System.Reflection.TypeExtensions.dll + ..\packages\System.Reflection.TypeExtensions.4.5.1\lib\net461\System.Reflection.TypeExtensions.dll ..\packages\System.Runtime.4.3.0\lib\net462\System.Runtime.dll True - - ..\packages\System.Runtime.CompilerServices.Unsafe.4.5.2\lib\netstandard2.0\System.Runtime.CompilerServices.Unsafe.dll + + ..\packages\System.Runtime.CompilerServices.Unsafe.4.6.0\lib\netstandard2.0\System.Runtime.CompilerServices.Unsafe.dll ..\packages\System.Runtime.Serialization.Primitives.4.1.1\lib\net46\System.Runtime.Serialization.Primitives.dll True + ..\packages\System.Security.Cryptography.Algorithms.4.3.0\lib\net463\System.Security.Cryptography.Algorithms.dll True @@ -196,6 +332,9 @@ ..\packages\System.Security.Cryptography.Primitives.4.3.0\lib\net46\System.Security.Cryptography.Primitives.dll True + + ..\packages\System.Security.Cryptography.ProtectedData.4.5.0\lib\net461\System.Security.Cryptography.ProtectedData.dll + ..\packages\System.Security.Cryptography.X509Certificates.4.3.0\lib\net461\System.Security.Cryptography.X509Certificates.dll True @@ -203,8 +342,20 @@ ..\packages\System.Spatial.5.8.4\lib\net40\System.Spatial.dll - - ..\packages\System.Threading.Tasks.Extensions.4.5.1\lib\portable-net45+win8+wp8+wpa81\System.Threading.Tasks.Extensions.dll + + ..\packages\System.Text.Encodings.Web.4.7.2\lib\net461\System.Text.Encodings.Web.dll + + + ..\packages\System.Text.Json.4.6.0\lib\net461\System.Text.Json.dll + + + ..\packages\System.Threading.Channels.4.6.0\lib\netstandard2.0\System.Threading.Channels.dll + + + ..\packages\System.Threading.Tasks.Dataflow.4.8.0\lib\netstandard2.0\System.Threading.Tasks.Dataflow.dll + + + ..\packages\System.Threading.Tasks.Extensions.4.5.4\lib\net461\System.Threading.Tasks.Extensions.dll ..\packages\System.ValueTuple.4.5.0\lib\netstandard1.0\System.ValueTuple.dll @@ -310,15 +461,19 @@ + + + + @@ -378,7 +533,7 @@ - + DiagnosticAnalysis\%(RecursiveDir)%(Filename)%(Extension) PreserveNewest diff --git a/DiagnosticsExtension/Models/ConnectionStringValidator/BlobStorageValidator.cs b/DiagnosticsExtension/Models/ConnectionStringValidator/BlobStorageValidator.cs new file mode 100644 index 00000000..c878121d --- /dev/null +++ b/DiagnosticsExtension/Models/ConnectionStringValidator/BlobStorageValidator.cs @@ -0,0 +1,192 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. +// +// ----------------------------------------------------------------------- + +using DiagnosticsExtension.Controllers; +using DiagnosticsExtension.Models.ConnectionStringValidator.Exceptions; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Azure.Storage.Blobs; +using Azure.Storage.Queues; +using Azure.Storage.Blobs.Models; +using Microsoft.WindowsAzure.Storage; + +namespace DiagnosticsExtension.Models.ConnectionStringValidator +{ + public class BlobStorageValidator : IConnectionStringValidator + { + public string ProviderName => "Microsoft.WindowsAzure.Storage"; + + public ConnectionStringType Type => ConnectionStringType.BlobStorageAccount; + + ConnectionStringValidationResult.ManagedIdentityType identityType; + + public async Task ValidateViaAppsettingAsync(string appsettingname, string entityName) + { + var response = new ConnectionStringValidationResult(Type); + + try + { + var result = await TestConnectionStringViaAppSetting(appsettingname, entityName); + if (result.Succeeded) + { + response.Status = ConnectionStringValidationResult.ResultStatus.Success; + } + else + { + throw new Exception("Unexpected state reached: result.Succeeded == false is unexpected!"); + } + } + catch (Exception e) + { + if (e is MalformedConnectionStringException) + { + response.Status = ConnectionStringValidationResult.ResultStatus.MalformedConnectionString; + } + else if (e.Message.Contains("managedidentitymissed")) + { + response.Status = ConnectionStringValidationResult.ResultStatus.managedidentitymissed; + } + else if (e.Message.Contains("Unauthorized") || e.Message.Contains("AuthorizationPermissionMismatch")) + { + if (identityType == ConnectionStringValidationResult.ManagedIdentityType.User) + { + response.Status = ConnectionStringValidationResult.ResultStatus.userAssignedmanagedidentity; + } + else + { + response.Status = ConnectionStringValidationResult.ResultStatus.systemAssignedmanagedidentity; + } + } + else if (e.Message.Contains("ManagedIdentityCredential")) + { + response.Status = ConnectionStringValidationResult.ResultStatus.managedIdentityCredential; + } + else if (e.Message.Contains("fullyQualifiedNamespacemissed")) + { + response.Status = ConnectionStringValidationResult.ResultStatus.fullyQualifiedNamespacemissed; + } + else if (e is EmptyConnectionStringException) + { + response.Status = ConnectionStringValidationResult.ResultStatus.EmptyConnectionString; + } + else if (e.InnerException != null && + e.InnerException.Message.Contains("The remote name could not be resolved")) + { + response.Status = ConnectionStringValidationResult.ResultStatus.DnsLookupFailed; + } + else if (e is StorageException) + { + if (((StorageException)e).RequestInformation.HttpStatusCode == 401) + { + response.Status = ConnectionStringValidationResult.ResultStatus.AuthFailure; + } + else if (((StorageException)e).RequestInformation.HttpStatusCode == 403) + { + response.Status = ConnectionStringValidationResult.ResultStatus.Forbidden; + } + } + else + { + response.Status = ConnectionStringValidationResult.ResultStatus.UnknownError; + } + response.Exception = e; + } + + return response; + } + + public async Task TestConnectionStringViaAppSetting(string appSettingName, string entityName) + { + var envDict = Environment.GetEnvironmentVariables(); + string appSettingClientIdValue, appSettingClientCredValue = null; + string value = null; + BlobServiceClient client = null; + + if (envDict.Contains(appSettingName)) + { + try + { + value = Environment.GetEnvironmentVariable(appSettingName); + client = new BlobServiceClient(value); + } + catch (ArgumentNullException e) + { + throw new EmptyConnectionStringException(e.Message, e); + } + catch (Exception e) + { + throw new MalformedConnectionStringException(e.Message, e); + } + } + else + { + try + { + + + value = Environment.GetEnvironmentVariable(appSettingName + "__blobServiceUri"); + if (!string.IsNullOrEmpty(value)) + { + appSettingClientIdValue = Environment.GetEnvironmentVariable(appSettingName + "__clientId"); + appSettingClientCredValue = Environment.GetEnvironmentVariable(appSettingName + "__credential"); + Uri objuri = new Uri(value); + if (!string.IsNullOrEmpty(appSettingClientIdValue)) + { + if (appSettingClientCredValue != "managedidentity") + { + throw new ManagedIdentityException("managedidentitymissed"); + } + else + { + identityType = ConnectionStringValidationResult.ManagedIdentityType.User; + client = new BlobServiceClient(objuri, new Azure.Identity.ManagedIdentityCredential(appSettingClientIdValue)); + } + } + else + { + identityType = ConnectionStringValidationResult.ManagedIdentityType.System; + client = new BlobServiceClient(objuri, new Azure.Identity.ManagedIdentityCredential()); + } + } + else + { + throw new ManagedIdentityException("fullyQualifiedNamespacemissed"); + } + } + catch (Exception e) + { + throw new ManagedIdentityException(e.Message, e); + } + } + client.GetBlobContainersAsync(); + var resultSegment = + client.GetBlobContainers(BlobContainerTraits.Metadata, null, default) + .AsPages(default, 10); + //connection autherization check + resultSegment.Single(); + + TestConnectionData data = new TestConnectionData + { + ConnectionString = client.ToString(), + Succeeded = true + }; + return data; + } + + public async Task ValidateAsync(string connStr, string clientId = null) + { + throw new NotImplementedException(); + } + public async Task IsValidAsync(string connStr) + { + throw new NotImplementedException(); + } + + } +} diff --git a/DiagnosticsExtension/Models/ConnectionStringValidator/ConnectionStringType.cs b/DiagnosticsExtension/Models/ConnectionStringValidator/ConnectionStringType.cs index db27c2f4..40c58d53 100644 --- a/DiagnosticsExtension/Models/ConnectionStringValidator/ConnectionStringType.cs +++ b/DiagnosticsExtension/Models/ConnectionStringValidator/ConnectionStringType.cs @@ -21,6 +21,9 @@ public enum ConnectionStringType RedisCache, StorageAccount, ServiceBus, - EventHubs - } -} \ No newline at end of file + EventHubs, + BlobStorageAccount, + QueueStorageAccount, + FileShareStorageAccount, + } +} diff --git a/DiagnosticsExtension/Models/ConnectionStringValidator/ConnectionStringValidationResult.cs b/DiagnosticsExtension/Models/ConnectionStringValidator/ConnectionStringValidationResult.cs index f061e58b..1b3fb875 100644 --- a/DiagnosticsExtension/Models/ConnectionStringValidator/ConnectionStringValidationResult.cs +++ b/DiagnosticsExtension/Models/ConnectionStringValidator/ConnectionStringValidationResult.cs @@ -40,9 +40,19 @@ public enum ResultStatus MsiFailure, EmptyConnectionString, MalformedConnectionString, - UnknownError + UnknownError, + managedidentitymissed, + fullyQualifiedNamespacemissed, + systemAssignedmanagedidentity, + userAssignedmanagedidentity, + managedIdentityCredential } + public enum ManagedIdentityType + { + User, + System + } + - } -} \ No newline at end of file +} diff --git a/DiagnosticsExtension/Models/ConnectionStringValidator/EventHubsValidator.cs b/DiagnosticsExtension/Models/ConnectionStringValidator/EventHubsValidator.cs index 88048727..29ee7939 100644 --- a/DiagnosticsExtension/Models/ConnectionStringValidator/EventHubsValidator.cs +++ b/DiagnosticsExtension/Models/ConnectionStringValidator/EventHubsValidator.cs @@ -10,6 +10,8 @@ using Microsoft.Azure.EventHubs; using System; using System.Threading.Tasks; +using Azure.Identity; +using Azure.Messaging.EventHubs.Producer; namespace DiagnosticsExtension.Models.ConnectionStringValidator { @@ -18,19 +20,19 @@ public class EventHubsValidator : IConnectionStringValidator public string ProviderName => "Microsoft.Azure.EventHubs"; public ConnectionStringType Type => ConnectionStringType.EventHubs; + ConnectionStringValidationResult.ManagedIdentityType identityType; - public Task IsValidAsync(string connectionString) + public async Task IsValidAsync(string connectionString) { try { - new EventHubsConnectionStringBuilder(connectionString); + new EventHubProducerClient(connectionString); } catch (Exception) { - return Task.FromResult(false); + return false; } - - return Task.FromResult(true); + return true; } async public Task ValidateAsync(string connectionString, string clientId = null) @@ -95,10 +97,157 @@ protected async Task TestConnectionStringAsync(string connec Name = name, Succeeded = true }; - var client = EventHubClient.CreateFromConnectionString(connectionString); - await client.GetRuntimeInformationAsync(); + + var client = new EventHubProducerClient(connectionString); + await client.GetPartitionIdsAsync(); + await client.CloseAsync(); + + return data; + } + + async public Task ValidateViaAppsettingAsync(string appsettingName, string entityName) + { + var response = new ConnectionStringValidationResult(Type); + + try + { + var result = await TestConnectionStringViaAppSettingAsync(appsettingName, entityName); + if (result.Succeeded) + { + response.Status = ConnectionStringValidationResult.ResultStatus.Success; + } + else + { + throw new Exception("Unexpected state reached: result.Succeeded == false is unexpected!"); + } + } + catch (Exception e) + { + if (e is MalformedConnectionStringException) + { + response.Status = ConnectionStringValidationResult.ResultStatus.MalformedConnectionString; + } + else if (e.Message.Contains("managedidentitymissed")) + { + response.Status = ConnectionStringValidationResult.ResultStatus.managedidentitymissed; + } + else if (e.Message.Contains("Unauthorized") || e.Message.Contains("unauthorized")) + { + if (identityType == ConnectionStringValidationResult.ManagedIdentityType.User) + { + response.Status = ConnectionStringValidationResult.ResultStatus.userAssignedmanagedidentity; + } + else + { + response.Status = ConnectionStringValidationResult.ResultStatus.systemAssignedmanagedidentity; + } + } + else if (e.Message.Contains("ManagedIdentityCredential")) + { + response.Status = ConnectionStringValidationResult.ResultStatus.managedIdentityCredential; + } + else if (e.Message.Contains("fullyQualifiedNamespacemissed")) + { + response.Status = ConnectionStringValidationResult.ResultStatus.fullyQualifiedNamespacemissed; + } + else if (e is EmptyConnectionStringException) + { + response.Status = ConnectionStringValidationResult.ResultStatus.EmptyConnectionString; + } + else if (e is ArgumentNullException || + e.Message.Contains("could not be found") || + e.Message.Contains("was not found")) + { + response.Status = ConnectionStringValidationResult.ResultStatus.MalformedConnectionString; + } + else if (e.Message.Contains("No such host is known")) + { + response.Status = ConnectionStringValidationResult.ResultStatus.DnsLookupFailed; + } + else if (e.Message.Contains("InvalidSignature") || + e.Message.Contains("Unauthorized")) + { + response.Status = ConnectionStringValidationResult.ResultStatus.AuthFailure; + } + else if (e.Message.Contains("Ip has been prevented to connect to the endpoint")) + { + response.Status = ConnectionStringValidationResult.ResultStatus.Forbidden; + } + else + { + response.Status = ConnectionStringValidationResult.ResultStatus.UnknownError; + } + response.Exception = e; + } + + return response; + } + protected async Task TestConnectionStringViaAppSettingAsync(string appSettingName, string entityName) + { + string value, appSettingClientIdValue, appSettingClientCredValue = ""; + EventHubProducerClient client = null; + var envDict = Environment.GetEnvironmentVariables(); + string eventHubName = entityName; + + if (envDict.Contains(appSettingName)) + { + try + { + value = Environment.GetEnvironmentVariable(appSettingName); + client = new EventHubProducerClient(value); + } + catch (Exception e) + { + throw new MalformedConnectionStringException(e.Message, e); + } + } + else + { + try + { + value = Environment.GetEnvironmentVariable(appSettingName + "__fullyQualifiedNamespace"); + if (!string.IsNullOrEmpty(value)) + { + appSettingClientIdValue = Environment.GetEnvironmentVariable(appSettingName + "__clientId"); + appSettingClientCredValue = Environment.GetEnvironmentVariable(appSettingName + "__credential"); + if (!string.IsNullOrEmpty(appSettingClientIdValue)) + { + if (appSettingClientCredValue != "managedidentity") + { + throw new ManagedIdentityException("managedidentitymissed"); + } + else + { + identityType = ConnectionStringValidationResult.ManagedIdentityType.User; + client = new EventHubProducerClient(value, eventHubName, new ManagedIdentityCredential(appSettingClientIdValue)); + } + } + else + { + identityType = ConnectionStringValidationResult.ManagedIdentityType.System; + client = new EventHubProducerClient(value, eventHubName, new ManagedIdentityCredential()); + } + } + else + { + throw new ManagedIdentityException("fullyQualifiedNamespacemissed"); + } + } + catch (Exception e) + { + throw new ManagedIdentityException(e.Message, e); + } + + } + await client.GetPartitionIdsAsync(); await client.CloseAsync(); + TestConnectionData data = new TestConnectionData + { + ConnectionString = client.ToString(), + Succeeded = true + }; + return data; } } diff --git a/DiagnosticsExtension/Models/ConnectionStringValidator/Exceptions/ManagedIdentityException.cs b/DiagnosticsExtension/Models/ConnectionStringValidator/Exceptions/ManagedIdentityException.cs new file mode 100644 index 00000000..f905d8d9 --- /dev/null +++ b/DiagnosticsExtension/Models/ConnectionStringValidator/Exceptions/ManagedIdentityException.cs @@ -0,0 +1,29 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. +// +// ----------------------------------------------------------------------- + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Web; + +namespace DiagnosticsExtension.Models.ConnectionStringValidator.Exceptions +{ + public class ManagedIdentityException : Exception + { + public ManagedIdentityException() : base() + { + } + + public ManagedIdentityException(string message) : base(message) + { + } + + public ManagedIdentityException(string message, Exception innerException) : base(message, innerException) + { + } + } +} diff --git a/DiagnosticsExtension/Models/ConnectionStringValidator/FileShareStorageValidator.cs b/DiagnosticsExtension/Models/ConnectionStringValidator/FileShareStorageValidator.cs new file mode 100644 index 00000000..8a48fd11 --- /dev/null +++ b/DiagnosticsExtension/Models/ConnectionStringValidator/FileShareStorageValidator.cs @@ -0,0 +1,207 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. +// +// ----------------------------------------------------------------------- + +using DiagnosticsExtension.Controllers; +using DiagnosticsExtension.Models.ConnectionStringValidator.Exceptions; +//using Microsoft.WindowsAzure.Storage; +//using Microsoft.WindowsAzure.Storage.Blob; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Azure.Storage.Blobs; +using Azure.Storage.Queues; +using Azure.Storage.Files; +using Azure.Storage.Files.Shares; +using Microsoft.WindowsAzure.Storage; + +namespace DiagnosticsExtension.Models.ConnectionStringValidator +{ + public class FileShareStorageValidator : IConnectionStringValidator + { + public string ProviderName => "Microsoft.WindowsAzure.Storage"; + + public ConnectionStringType Type => ConnectionStringType.FileShareStorageAccount; + + public async Task IsValidAsync(string connStr) + { + try + { + Uri objuri = new Uri(connStr); + ShareServiceClient client = new ShareServiceClient(objuri); + } + catch (Exception) + { + return false; + } + return true; + } + + public async Task ValidateAsync(string connStr, string clientId = null) + { + var response = new ConnectionStringValidationResult(Type); + + try + { + var result = await TestConnectionString(connStr, null, clientId); + if (result.Succeeded) + { + response.Status = ConnectionStringValidationResult.ResultStatus.Success; + } + else + { + throw new Exception("Unexpected state reached: result.Succeeded == false is unexpected!"); + } + } + catch (Exception e) + { + if (e is MalformedConnectionStringException) + { + response.Status = ConnectionStringValidationResult.ResultStatus.MalformedConnectionString; + } + else if (e is EmptyConnectionStringException) + { + response.Status = ConnectionStringValidationResult.ResultStatus.EmptyConnectionString; + } + else if (e.InnerException != null && + e.InnerException.Message.Contains("The remote name could not be resolved")) + { + response.Status = ConnectionStringValidationResult.ResultStatus.DnsLookupFailed; + } + else if (e is StorageException) + { + if (((StorageException)e).RequestInformation.HttpStatusCode == 401) + { + response.Status = ConnectionStringValidationResult.ResultStatus.AuthFailure; + } + else if (((StorageException)e).RequestInformation.HttpStatusCode == 403) + { + response.Status = ConnectionStringValidationResult.ResultStatus.Forbidden; + } + } + else + { + response.Status = ConnectionStringValidationResult.ResultStatus.UnknownError; + } + response.Exception = e; + } + + return response; + } + + public async Task TestConnectionString(string connectionString, string name, string clientId) + { + TestConnectionData data = new TestConnectionData + { + ConnectionString = connectionString, + Name = name, + Succeeded = true + }; + // CloudStorageAccount storageAccount; + try + { + //storageAccount = CloudStorageAccount.Parse(connectionString); + } + catch (ArgumentNullException e) + { + throw new EmptyConnectionStringException(e.Message, e); + } + catch (Exception e) + { + throw new MalformedConnectionStringException(e.Message, e); + } + + // CloudBlobClient client = storageAccount.CreateCloudBlobClient(); + // client.GetServiceProperties(); + // client.ListContainers(); + + return data; + } + + public async Task ValidateViaAppsettingAsync(string appsettingname, string entityName) + { + var response = new ConnectionStringValidationResult(Type); + + try + { + var result = await TestConnectionStringViaAppSetting(appsettingname, entityName); + if (result.Succeeded) + { + response.Status = ConnectionStringValidationResult.ResultStatus.Success; + } + else + { + throw new Exception("Unexpected state reached: result.Succeeded == false is unexpected!"); + } + } + catch (Exception e) + { + if (e is MalformedConnectionStringException) + { + response.Status = ConnectionStringValidationResult.ResultStatus.MalformedConnectionString; + } + else if (e is EmptyConnectionStringException) + { + response.Status = ConnectionStringValidationResult.ResultStatus.EmptyConnectionString; + } + else if (e.InnerException != null && + e.InnerException.Message.Contains("The remote name could not be resolved")) + { + response.Status = ConnectionStringValidationResult.ResultStatus.DnsLookupFailed; + } + //else if (e is StorageException) + //{ + // if (((StorageException)e).RequestInformation.HttpStatusCode == 401) + // { + // response.Status = ConnectionStringValidationResult.ResultStatus.AuthFailure; + // } + // else if (((StorageException)e).RequestInformation.HttpStatusCode == 403) + // { + // response.Status = ConnectionStringValidationResult.ResultStatus.Forbidden; + // } + //} + else + { + response.Status = ConnectionStringValidationResult.ResultStatus.UnknownError; + } + response.Exception = e; + } + + return response; + } + + public async Task TestConnectionStringViaAppSetting(string appSettingName, string entityName) + { + string value = ""; + var envDict = Environment.GetEnvironmentVariables(); + ShareServiceClient client = null; + try + { + if (envDict.Contains(appSettingName)) + { + value = Environment.GetEnvironmentVariable(appSettingName); + client = new ShareServiceClient(value); + } + client.GetSharesAsync(); + } + catch (ArgumentNullException e) + { + throw new EmptyConnectionStringException(e.Message, e); + } + catch (Exception e) + { + throw new MalformedConnectionStringException(e.Message, e); + } + TestConnectionData data = new TestConnectionData + { + ConnectionString = client.ToString(), + Succeeded = true + }; + return data; + } + } +} diff --git a/DiagnosticsExtension/Models/ConnectionStringValidator/HttpValidator.cs b/DiagnosticsExtension/Models/ConnectionStringValidator/HttpValidator.cs index 79e6f86e..66e4a456 100644 --- a/DiagnosticsExtension/Models/ConnectionStringValidator/HttpValidator.cs +++ b/DiagnosticsExtension/Models/ConnectionStringValidator/HttpValidator.cs @@ -103,5 +103,9 @@ async public Task ValidateAsync(string connStr return response; } + public async Task ValidateViaAppsettingAsync(string appsettingName, string entityName) + { + throw new NotImplementedException(); + } } } diff --git a/DiagnosticsExtension/Models/ConnectionStringValidator/IConnectionStringValidator.cs b/DiagnosticsExtension/Models/ConnectionStringValidator/IConnectionStringValidator.cs index 106ad24d..7bf1d9a1 100644 --- a/DiagnosticsExtension/Models/ConnectionStringValidator/IConnectionStringValidator.cs +++ b/DiagnosticsExtension/Models/ConnectionStringValidator/IConnectionStringValidator.cs @@ -19,7 +19,7 @@ interface IConnectionStringValidator Task IsValidAsync(string connStr); Task ValidateAsync(string connStr, string clientId = null); // clientId used for Used Assigned Managed Identity - + Task ValidateViaAppsettingAsync(string appSettingName, string entityName = null); string ProviderName { get; } ConnectionStringType Type { get; } diff --git a/DiagnosticsExtension/Models/ConnectionStringValidator/KeyVaultValidator.cs b/DiagnosticsExtension/Models/ConnectionStringValidator/KeyVaultValidator.cs index 54d8b178..38d33b9f 100644 --- a/DiagnosticsExtension/Models/ConnectionStringValidator/KeyVaultValidator.cs +++ b/DiagnosticsExtension/Models/ConnectionStringValidator/KeyVaultValidator.cs @@ -155,5 +155,9 @@ async public Task ValidateAsync(string connStr return response; } + public async Task ValidateViaAppsettingAsync(string appsettingName, string entityName) + { + throw new NotImplementedException(); + } } } diff --git a/DiagnosticsExtension/Models/ConnectionStringValidator/MySqlValidator.cs b/DiagnosticsExtension/Models/ConnectionStringValidator/MySqlValidator.cs index d928eb37..05c2e007 100644 --- a/DiagnosticsExtension/Models/ConnectionStringValidator/MySqlValidator.cs +++ b/DiagnosticsExtension/Models/ConnectionStringValidator/MySqlValidator.cs @@ -111,5 +111,9 @@ public async Task TestMySqlConnectionString(string connectio return data; } + public async Task ValidateViaAppsettingAsync(string appsettingName, string entityName) + { + throw new NotImplementedException(); + } } } diff --git a/DiagnosticsExtension/Models/ConnectionStringValidator/QueueStorageValidator.cs b/DiagnosticsExtension/Models/ConnectionStringValidator/QueueStorageValidator.cs new file mode 100644 index 00000000..f1f24182 --- /dev/null +++ b/DiagnosticsExtension/Models/ConnectionStringValidator/QueueStorageValidator.cs @@ -0,0 +1,199 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. +// +// ----------------------------------------------------------------------- + +using DiagnosticsExtension.Controllers; +using DiagnosticsExtension.Models.ConnectionStringValidator.Exceptions; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Azure.Storage.Blobs; +using Azure.Storage.Queues; +using Azure.Storage.Files; +using Azure.Storage.Queues.Models; +using Microsoft.WindowsAzure.Storage; + +namespace DiagnosticsExtension.Models.ConnectionStringValidator +{ + public class QueueStorageValidator : IConnectionStringValidator + { + public string ProviderName => "Microsoft.WindowsAzure.Storage"; + + public ConnectionStringType Type => ConnectionStringType.QueueStorageAccount; + ConnectionStringValidationResult.ManagedIdentityType identityType; + + public async Task ValidateViaAppsettingAsync(string appsettingname, string entityName) + { + var response = new ConnectionStringValidationResult(Type); + + try + { + var result = await TestConnectionStringViaAppSetting(appsettingname, entityName); + if (result.Succeeded) + { + response.Status = ConnectionStringValidationResult.ResultStatus.Success; + } + else + { + throw new Exception("Unexpected state reached: result.Succeeded == false is unexpected!"); + } + } + catch (Exception e) + { + if (e is MalformedConnectionStringException) + { + response.Status = ConnectionStringValidationResult.ResultStatus.MalformedConnectionString; + } + else if (e.Message.Contains("managedidentitymissed")) + { + response.Status = ConnectionStringValidationResult.ResultStatus.managedidentitymissed; + } + else if (e.Message.Contains("Unauthorized") || e.Message.Contains("AuthorizationPermissionMismatch")) + { + if (identityType == ConnectionStringValidationResult.ManagedIdentityType.User) + { + response.Status = ConnectionStringValidationResult.ResultStatus.userAssignedmanagedidentity; + } + else + { + response.Status = ConnectionStringValidationResult.ResultStatus.systemAssignedmanagedidentity; + } + } + else if (e.Message.Contains("ManagedIdentityCredential")) + { + response.Status = ConnectionStringValidationResult.ResultStatus.managedIdentityCredential; + } + else if (e.Message.Contains("fullyQualifiedNamespacemissed")) + { + response.Status = ConnectionStringValidationResult.ResultStatus.fullyQualifiedNamespacemissed; + } + else if (e is EmptyConnectionStringException) + { + response.Status = ConnectionStringValidationResult.ResultStatus.EmptyConnectionString; + } + else if (e.InnerException != null && + e.InnerException.Message.Contains("The remote name could not be resolved")) + { + response.Status = ConnectionStringValidationResult.ResultStatus.DnsLookupFailed; + } + else if (e is StorageException) + { + if (((StorageException)e).RequestInformation.HttpStatusCode == 401) + { + response.Status = ConnectionStringValidationResult.ResultStatus.AuthFailure; + } + else if (((StorageException)e).RequestInformation.HttpStatusCode == 403) + { + response.Status = ConnectionStringValidationResult.ResultStatus.Forbidden; + } + } + else + { + response.Status = ConnectionStringValidationResult.ResultStatus.UnknownError; + } + response.Exception = e; + } + + return response; + } + + public async Task TestConnectionStringViaAppSetting(string appSettingName, string entityName) + { + var envDict = Environment.GetEnvironmentVariables(); + string appSettingClientIdValue, appSettingClientCredValue = null; + string value = null; + QueueServiceClient client = null; + + if (envDict.Contains(appSettingName)) + { + try + { + value = Environment.GetEnvironmentVariable(appSettingName); + client = new QueueServiceClient(value); + } + catch (ArgumentNullException e) + { + throw new EmptyConnectionStringException(e.Message, e); + } + catch (Exception e) + { + throw new MalformedConnectionStringException(e.Message, e); + } + + } + else + { + try + { + + + value = Environment.GetEnvironmentVariable(appSettingName + "__queueServiceUri"); + if (!string.IsNullOrEmpty(value)) + { + appSettingClientIdValue = Environment.GetEnvironmentVariable(appSettingName + "__clientId"); + appSettingClientCredValue = Environment.GetEnvironmentVariable(appSettingName + "__credential"); + Uri objuri = new Uri(value); + if (!string.IsNullOrEmpty(appSettingClientIdValue)) + { + if (appSettingClientCredValue != "managedidentity") + { + throw new ManagedIdentityException("managedidentitymissed"); + } + else + { + identityType = ConnectionStringValidationResult.ManagedIdentityType.User; + client = new QueueServiceClient(objuri, new Azure.Identity.ManagedIdentityCredential(appSettingClientIdValue)); + } + + } + else + { + identityType = ConnectionStringValidationResult.ManagedIdentityType.System; + client = new QueueServiceClient(objuri, new Azure.Identity.ManagedIdentityCredential()); + } + } + else + { + throw new ManagedIdentityException("fullyQualifiedNamespacemissed"); + } + } + catch (Exception e) + { + throw new ManagedIdentityException(e.Message, e); + } + } + client.GetQueuesAsync(); + var resultSegment = + client.GetQueues(QueueTraits.Metadata, null, default) + .AsPages(default, 10); + foreach (Azure.Page containerPage in resultSegment) + { + foreach (QueueItem containerItem in containerPage.Values) + { + string containerName = containerItem.Name.ToString(); + } + + } + + + TestConnectionData data = new TestConnectionData + { + ConnectionString = client.ToString(), + Succeeded = true + }; + return data; + } + public async Task ValidateAsync(string connStr, string clientId = null) + { + throw new NotImplementedException(); + } + public async Task IsValidAsync(string connStr) + { + throw new NotImplementedException(); + } + } +} diff --git a/DiagnosticsExtension/Models/ConnectionStringValidator/ServiceBusValidator.cs b/DiagnosticsExtension/Models/ConnectionStringValidator/ServiceBusValidator.cs index 42b1986e..db1712ef 100644 --- a/DiagnosticsExtension/Models/ConnectionStringValidator/ServiceBusValidator.cs +++ b/DiagnosticsExtension/Models/ConnectionStringValidator/ServiceBusValidator.cs @@ -13,6 +13,7 @@ using System; using System.Linq; using System.Threading.Tasks; +using Azure.Messaging.ServiceBus; namespace DiagnosticsExtension.Models.ConnectionStringValidator { @@ -21,18 +22,19 @@ public class ServiceBusValidator : IConnectionStringValidator public string ProviderName => "Microsoft.Azure.ServiceBus"; public ConnectionStringType Type => ConnectionStringType.ServiceBus; - - public Task IsValidAsync(string connectionString) + public Azure.Messaging.ServiceBus.ServiceBusReceiveMode ReceiveMode { get; set; } + ConnectionStringValidationResult.ManagedIdentityType identityType; + public async Task IsValidAsync(string connectionString) { try { - new ServiceBusConnectionStringBuilder(connectionString); + new ServiceBusClient(connectionString); } catch (Exception) { - return Task.FromResult(false); + return false; } - return Task.FromResult(true); + return true; } async public Task ValidateAsync(string connectionString, string clientId = null) @@ -99,10 +101,12 @@ protected async Task TestConnectionStringAsync(string connec { throw new EmptyConnectionStringException(); } - ServiceBusConnectionStringBuilder connectionStringBuilder = null; + + ServiceBusClient client = null; try { - connectionStringBuilder = new ServiceBusConnectionStringBuilder(connectionString); + client = new ServiceBusClient(connectionString); + } catch (Exception e) { @@ -115,8 +119,162 @@ protected async Task TestConnectionStringAsync(string connec Succeeded = true }; - MessageReceiver msgReceiver = new MessageReceiver(connectionStringBuilder, ReceiveMode.PeekLock, prefetchCount: 1); - Message msg = await msgReceiver.PeekAsync(); + ServiceBusSessionProcessorOptions opt = new ServiceBusSessionProcessorOptions(); + opt.ReceiveMode = ServiceBusReceiveMode.PeekLock; + string entityPath = ServiceBusConnectionStringProperties.Parse(connectionString).EntityPath; + ServiceBusReceiver receiver = client.CreateReceiver(entityPath); + ServiceBusReceivedMessage receivedMessage = await receiver.PeekMessageAsync(); + + return data; + } + async public Task ValidateViaAppsettingAsync(string appsettingName, string entityName) + { + var response = new ConnectionStringValidationResult(Type); + + try + { + var result = await TestConnectionStringViaAppSettingAsync(appsettingName, entityName); + if (result.Succeeded) + { + response.Status = ConnectionStringValidationResult.ResultStatus.Success; + } + else + { + throw new Exception("Unexpected state reached: result.Succeeded == false is unexpected!"); + } + } + catch (Exception e) + { + if (e is MalformedConnectionStringException || e is ArgumentNullException) + { + response.Status = ConnectionStringValidationResult.ResultStatus.MalformedConnectionString; + } + else if (e.Message.Contains("managedidentitymissed")) + { + response.Status = ConnectionStringValidationResult.ResultStatus.managedidentitymissed; + } + else if (e.Message.Contains("Unauthorized")) + { + if (identityType == ConnectionStringValidationResult.ManagedIdentityType.User) + { + response.Status = ConnectionStringValidationResult.ResultStatus.userAssignedmanagedidentity; + } + else + { + response.Status = ConnectionStringValidationResult.ResultStatus.systemAssignedmanagedidentity; + } + } + else if (e.Message.Contains("ManagedIdentityCredential")) + { + response.Status = ConnectionStringValidationResult.ResultStatus.managedIdentityCredential; + } + else if (e.Message.Contains("fullyQualifiedNamespacemissed")) + { + response.Status = ConnectionStringValidationResult.ResultStatus.fullyQualifiedNamespacemissed; + } + else if (e is EmptyConnectionStringException) + { + response.Status = ConnectionStringValidationResult.ResultStatus.EmptyConnectionString; + } + else if ((e is ArgumentException && e.Message.Contains("Authentication ")) || + e.Message.Contains("claim is empty or token is invalid") || + e.Message.Contains("InvalidSignature") || + e.Message.Contains("Unauthorized")) + { + response.Status = ConnectionStringValidationResult.ResultStatus.AuthFailure; + } + else if (e is ArgumentException && e.Message.Contains("entityPath is null") || + e.Message.Contains("HostNotFound") || + e.Message.Contains("could not be found") || + e.Message.Contains("The argument is null or white space")) + { + response.Status = ConnectionStringValidationResult.ResultStatus.MalformedConnectionString; + } + else if (e.InnerException != null && e.InnerException.InnerException != null && + e.InnerException.InnerException.Message.Contains("The remote name could not be resolved")) + { + response.Status = ConnectionStringValidationResult.ResultStatus.DnsLookupFailed; + } + else if (e.Message.Contains("Ip has been prevented to connect to the endpoint")) + { + response.Status = ConnectionStringValidationResult.ResultStatus.Forbidden; + } + else + { + response.Status = ConnectionStringValidationResult.ResultStatus.UnknownError; + } + response.Exception = e; + } + + return response; + } + protected async Task TestConnectionStringViaAppSettingAsync(string appSettingName, string entityName) + { + string value, appSettingClientIdValue, appSettingClientCredValue = ""; + ServiceBusClient client = null; + var envDict = Environment.GetEnvironmentVariables(); + + if (envDict.Contains(appSettingName)) + { + try + { + value = Environment.GetEnvironmentVariable(appSettingName); + client = new ServiceBusClient(value); + } + catch (Exception e) + { + throw new MalformedConnectionStringException(e.Message, e); + } + + } + else + { + try + { + value = Environment.GetEnvironmentVariable(appSettingName + "__fullyQualifiedNamespace"); + if (!string.IsNullOrEmpty(value)) + { + appSettingClientIdValue = Environment.GetEnvironmentVariable(appSettingName + "__clientId"); + appSettingClientCredValue = Environment.GetEnvironmentVariable(appSettingName + "__credential"); + if (!string.IsNullOrEmpty(appSettingClientIdValue)) + { + if (appSettingClientCredValue != "managedidentity") + { + + throw new ManagedIdentityException("managedidentitymissed"); + } + else + { + identityType = ConnectionStringValidationResult.ManagedIdentityType.User; + client = new ServiceBusClient(value, new Azure.Identity.ManagedIdentityCredential(appSettingClientIdValue)); + } + } + else + { + identityType = ConnectionStringValidationResult.ManagedIdentityType.System; + client = new ServiceBusClient(value, new Azure.Identity.ManagedIdentityCredential()); + } + } + else + { + throw new ManagedIdentityException("fullyQualifiedNamespacemissed"); + } + } + catch (Exception e) + { + throw new ManagedIdentityException(e.Message, e); + } + } + TestConnectionData data = new TestConnectionData + { + ConnectionString = client.ToString(), + Succeeded = true + }; + ServiceBusReceiverOptions opt = new ServiceBusReceiverOptions(); + opt.ReceiveMode = ServiceBusReceiveMode.PeekLock; + opt.PrefetchCount = 1; + ServiceBusReceiver receiver = client.CreateReceiver(entityName, opt); + ServiceBusReceivedMessage receivedMessage = await receiver.PeekMessageAsync(); return data; } diff --git a/DiagnosticsExtension/Models/ConnectionStringValidator/SqlServerValidator.cs b/DiagnosticsExtension/Models/ConnectionStringValidator/SqlServerValidator.cs index 99927e81..76a25ac4 100644 --- a/DiagnosticsExtension/Models/ConnectionStringValidator/SqlServerValidator.cs +++ b/DiagnosticsExtension/Models/ConnectionStringValidator/SqlServerValidator.cs @@ -165,5 +165,9 @@ public async Task TestSqlServerConnectionString(string conne return data; } + public async Task ValidateViaAppsettingAsync(string appsettingName, string entityName) + { + throw new NotImplementedException(); + } } } diff --git a/DiagnosticsExtension/Models/ConnectionStringValidator/StorageValidator.cs b/DiagnosticsExtension/Models/ConnectionStringValidator/StorageValidator.cs index 706fc322..cb98aeec 100644 --- a/DiagnosticsExtension/Models/ConnectionStringValidator/StorageValidator.cs +++ b/DiagnosticsExtension/Models/ConnectionStringValidator/StorageValidator.cs @@ -115,5 +115,9 @@ public Task TestConnectionString(string connectionString, st return Task.FromResult(data); } + public async Task ValidateViaAppsettingAsync(string appsettingName, string entityName) + { + throw new NotImplementedException(); + } } } diff --git a/DiagnosticsExtension/Web.config b/DiagnosticsExtension/Web.config index 7bdd8e0f..fa13fbc4 100644 --- a/DiagnosticsExtension/Web.config +++ b/DiagnosticsExtension/Web.config @@ -102,7 +102,7 @@ - + @@ -122,7 +122,75 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/DiagnosticsExtension/packages.config b/DiagnosticsExtension/packages.config index b8621c12..955d5b08 100644 --- a/DiagnosticsExtension/packages.config +++ b/DiagnosticsExtension/packages.config @@ -1,6 +1,16 @@  + + + + + + + + + + @@ -18,17 +28,46 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -36,6 +75,7 @@ + @@ -44,27 +84,37 @@ + + - + + + + - + + - + + - + + + + + - \ No newline at end of file From 424453ae12f66c84688be811ccf8808ac7eea013 Mon Sep 17 00:00:00 2001 From: Gajibilli Koteswara Rao Date: Wed, 2 Feb 2022 20:56:19 +0530 Subject: [PATCH 02/26] Modified the code as per the comments --- .../ConnectionStringValidationController.cs | 5 +- .../BlobStorageValidator.cs | 16 ++- .../ConnectionStringValidationResult.cs | 10 +- .../EventHubsValidator.cs | 23 ++-- .../FileShareStorageValidator.cs | 110 ++---------------- .../QueueStorageValidator.cs | 10 +- .../ServiceBusValidator.cs | 33 +++--- 7 files changed, 56 insertions(+), 151 deletions(-) diff --git a/DiagnosticsExtension/Controllers/ConnectionStringValidationController.cs b/DiagnosticsExtension/Controllers/ConnectionStringValidationController.cs index 990b2a19..0f00a089 100644 --- a/DiagnosticsExtension/Controllers/ConnectionStringValidationController.cs +++ b/DiagnosticsExtension/Controllers/ConnectionStringValidationController.cs @@ -36,6 +36,7 @@ public ConnectionStringValidationController() new SqlServerValidator(), new MySqlValidator(), new KeyVaultValidator(), + new StorageValidator(), new BlobStorageValidator(), new QueueStorageValidator(), new FileShareStorageValidator(), @@ -74,7 +75,6 @@ public async Task Validate([FromBody] ConnectionStringReque { return Request.CreateErrorResponse(HttpStatusCode.BadRequest, "Type is not specified in the request body"); } - var result = await Validate(requestBody.ConnectionString, requestBody.Type); return result; } @@ -83,7 +83,6 @@ public async Task Validate([FromBody] ConnectionStringReque [Route("validateappsetting")] public async Task ValidateAppSetting(string appSettingName, string type, string entityName = null) { - bool success = Enum.TryParse(type, out ConnectionStringType csType); if (success && typeValidatorMap.ContainsKey(csType)) { @@ -94,8 +93,6 @@ public async Task ValidateAppSetting(string appSettingName, { return Request.CreateErrorResponse(HttpStatusCode.BadRequest, $"Type '{type}' is not supported"); } - } - } } diff --git a/DiagnosticsExtension/Models/ConnectionStringValidator/BlobStorageValidator.cs b/DiagnosticsExtension/Models/ConnectionStringValidator/BlobStorageValidator.cs index c878121d..2637e589 100644 --- a/DiagnosticsExtension/Models/ConnectionStringValidator/BlobStorageValidator.cs +++ b/DiagnosticsExtension/Models/ConnectionStringValidator/BlobStorageValidator.cs @@ -50,26 +50,26 @@ public async Task ValidateViaAppsettingAsync(s } else if (e.Message.Contains("managedidentitymissed")) { - response.Status = ConnectionStringValidationResult.ResultStatus.managedidentitymissed; + response.Status = ConnectionStringValidationResult.ResultStatus.Managedidentitymissed; } else if (e.Message.Contains("Unauthorized") || e.Message.Contains("AuthorizationPermissionMismatch")) { if (identityType == ConnectionStringValidationResult.ManagedIdentityType.User) { - response.Status = ConnectionStringValidationResult.ResultStatus.userAssignedmanagedidentity; + response.Status = ConnectionStringValidationResult.ResultStatus.UserAssignedmanagedidentity; } else { - response.Status = ConnectionStringValidationResult.ResultStatus.systemAssignedmanagedidentity; + response.Status = ConnectionStringValidationResult.ResultStatus.SystemAssignedmanagedidentity; } } else if (e.Message.Contains("ManagedIdentityCredential")) { - response.Status = ConnectionStringValidationResult.ResultStatus.managedIdentityCredential; + response.Status = ConnectionStringValidationResult.ResultStatus.ManagedIdentityCredential; } else if (e.Message.Contains("fullyQualifiedNamespacemissed")) { - response.Status = ConnectionStringValidationResult.ResultStatus.fullyQualifiedNamespacemissed; + response.Status = ConnectionStringValidationResult.ResultStatus.FullyQualifiedNamespacemissed; } else if (e is EmptyConnectionStringException) { @@ -131,6 +131,10 @@ public async Task TestConnectionStringViaAppSetting(string a value = Environment.GetEnvironmentVariable(appSettingName + "__blobServiceUri"); + if (string.IsNullOrEmpty(value)) + { + value = Environment.GetEnvironmentVariable(appSettingName + "__serviceUri"); + } if (!string.IsNullOrEmpty(value)) { appSettingClientIdValue = Environment.GetEnvironmentVariable(appSettingName + "__clientId"); @@ -168,7 +172,7 @@ public async Task TestConnectionStringViaAppSetting(string a var resultSegment = client.GetBlobContainers(BlobContainerTraits.Metadata, null, default) .AsPages(default, 10); - //connection autherization check + //need to read at least one result item to confirm authorization check for connection resultSegment.Single(); TestConnectionData data = new TestConnectionData diff --git a/DiagnosticsExtension/Models/ConnectionStringValidator/ConnectionStringValidationResult.cs b/DiagnosticsExtension/Models/ConnectionStringValidator/ConnectionStringValidationResult.cs index 1b3fb875..fa8c0684 100644 --- a/DiagnosticsExtension/Models/ConnectionStringValidator/ConnectionStringValidationResult.cs +++ b/DiagnosticsExtension/Models/ConnectionStringValidator/ConnectionStringValidationResult.cs @@ -41,11 +41,11 @@ public enum ResultStatus EmptyConnectionString, MalformedConnectionString, UnknownError, - managedidentitymissed, - fullyQualifiedNamespacemissed, - systemAssignedmanagedidentity, - userAssignedmanagedidentity, - managedIdentityCredential + Managedidentitymissed, + FullyQualifiedNamespacemissed, + SystemAssignedmanagedidentity, + UserAssignedmanagedidentity, + ManagedIdentityCredential } public enum ManagedIdentityType { diff --git a/DiagnosticsExtension/Models/ConnectionStringValidator/EventHubsValidator.cs b/DiagnosticsExtension/Models/ConnectionStringValidator/EventHubsValidator.cs index 29ee7939..c801f806 100644 --- a/DiagnosticsExtension/Models/ConnectionStringValidator/EventHubsValidator.cs +++ b/DiagnosticsExtension/Models/ConnectionStringValidator/EventHubsValidator.cs @@ -22,17 +22,17 @@ public class EventHubsValidator : IConnectionStringValidator public ConnectionStringType Type => ConnectionStringType.EventHubs; ConnectionStringValidationResult.ManagedIdentityType identityType; - public async Task IsValidAsync(string connectionString) + public Task IsValidAsync(string connectionString) { try { - new EventHubProducerClient(connectionString); + new EventHubsConnectionStringBuilder(connectionString); } catch (Exception) { - return false; + return Task.FromResult(false); } - return true; + return Task.FromResult(true); } async public Task ValidateAsync(string connectionString, string clientId = null) @@ -97,9 +97,8 @@ protected async Task TestConnectionStringAsync(string connec Name = name, Succeeded = true }; - - var client = new EventHubProducerClient(connectionString); - await client.GetPartitionIdsAsync(); + var client = EventHubClient.CreateFromConnectionString(connectionString); + await client.GetRuntimeInformationAsync(); await client.CloseAsync(); return data; @@ -129,26 +128,26 @@ async public Task ValidateViaAppsettingAsync(s } else if (e.Message.Contains("managedidentitymissed")) { - response.Status = ConnectionStringValidationResult.ResultStatus.managedidentitymissed; + response.Status = ConnectionStringValidationResult.ResultStatus.Managedidentitymissed; } else if (e.Message.Contains("Unauthorized") || e.Message.Contains("unauthorized")) { if (identityType == ConnectionStringValidationResult.ManagedIdentityType.User) { - response.Status = ConnectionStringValidationResult.ResultStatus.userAssignedmanagedidentity; + response.Status = ConnectionStringValidationResult.ResultStatus.UserAssignedmanagedidentity; } else { - response.Status = ConnectionStringValidationResult.ResultStatus.systemAssignedmanagedidentity; + response.Status = ConnectionStringValidationResult.ResultStatus.SystemAssignedmanagedidentity; } } else if (e.Message.Contains("ManagedIdentityCredential")) { - response.Status = ConnectionStringValidationResult.ResultStatus.managedIdentityCredential; + response.Status = ConnectionStringValidationResult.ResultStatus.ManagedIdentityCredential; } else if (e.Message.Contains("fullyQualifiedNamespacemissed")) { - response.Status = ConnectionStringValidationResult.ResultStatus.fullyQualifiedNamespacemissed; + response.Status = ConnectionStringValidationResult.ResultStatus.FullyQualifiedNamespacemissed; } else if (e is EmptyConnectionStringException) { diff --git a/DiagnosticsExtension/Models/ConnectionStringValidator/FileShareStorageValidator.cs b/DiagnosticsExtension/Models/ConnectionStringValidator/FileShareStorageValidator.cs index 8a48fd11..6033fca2 100644 --- a/DiagnosticsExtension/Models/ConnectionStringValidator/FileShareStorageValidator.cs +++ b/DiagnosticsExtension/Models/ConnectionStringValidator/FileShareStorageValidator.cs @@ -7,8 +7,6 @@ using DiagnosticsExtension.Controllers; using DiagnosticsExtension.Models.ConnectionStringValidator.Exceptions; -//using Microsoft.WindowsAzure.Storage; -//using Microsoft.WindowsAzure.Storage.Blob; using System; using System.Collections.Generic; using System.Linq; @@ -26,28 +24,13 @@ public class FileShareStorageValidator : IConnectionStringValidator public string ProviderName => "Microsoft.WindowsAzure.Storage"; public ConnectionStringType Type => ConnectionStringType.FileShareStorageAccount; - - public async Task IsValidAsync(string connStr) - { - try - { - Uri objuri = new Uri(connStr); - ShareServiceClient client = new ShareServiceClient(objuri); - } - catch (Exception) - { - return false; - } - return true; - } - - public async Task ValidateAsync(string connStr, string clientId = null) + public async Task ValidateViaAppsettingAsync(string appsettingname, string entityName) { var response = new ConnectionStringValidationResult(Type); try { - var result = await TestConnectionString(connStr, null, clientId); + var result = await TestConnectionStringViaAppSetting(appsettingname, entityName); if (result.Succeeded) { response.Status = ConnectionStringValidationResult.ResultStatus.Success; @@ -93,87 +76,6 @@ public async Task ValidateAsync(string connStr return response; } - public async Task TestConnectionString(string connectionString, string name, string clientId) - { - TestConnectionData data = new TestConnectionData - { - ConnectionString = connectionString, - Name = name, - Succeeded = true - }; - // CloudStorageAccount storageAccount; - try - { - //storageAccount = CloudStorageAccount.Parse(connectionString); - } - catch (ArgumentNullException e) - { - throw new EmptyConnectionStringException(e.Message, e); - } - catch (Exception e) - { - throw new MalformedConnectionStringException(e.Message, e); - } - - // CloudBlobClient client = storageAccount.CreateCloudBlobClient(); - // client.GetServiceProperties(); - // client.ListContainers(); - - return data; - } - - public async Task ValidateViaAppsettingAsync(string appsettingname, string entityName) - { - var response = new ConnectionStringValidationResult(Type); - - try - { - var result = await TestConnectionStringViaAppSetting(appsettingname, entityName); - if (result.Succeeded) - { - response.Status = ConnectionStringValidationResult.ResultStatus.Success; - } - else - { - throw new Exception("Unexpected state reached: result.Succeeded == false is unexpected!"); - } - } - catch (Exception e) - { - if (e is MalformedConnectionStringException) - { - response.Status = ConnectionStringValidationResult.ResultStatus.MalformedConnectionString; - } - else if (e is EmptyConnectionStringException) - { - response.Status = ConnectionStringValidationResult.ResultStatus.EmptyConnectionString; - } - else if (e.InnerException != null && - e.InnerException.Message.Contains("The remote name could not be resolved")) - { - response.Status = ConnectionStringValidationResult.ResultStatus.DnsLookupFailed; - } - //else if (e is StorageException) - //{ - // if (((StorageException)e).RequestInformation.HttpStatusCode == 401) - // { - // response.Status = ConnectionStringValidationResult.ResultStatus.AuthFailure; - // } - // else if (((StorageException)e).RequestInformation.HttpStatusCode == 403) - // { - // response.Status = ConnectionStringValidationResult.ResultStatus.Forbidden; - // } - //} - else - { - response.Status = ConnectionStringValidationResult.ResultStatus.UnknownError; - } - response.Exception = e; - } - - return response; - } - public async Task TestConnectionStringViaAppSetting(string appSettingName, string entityName) { string value = ""; @@ -203,5 +105,13 @@ public async Task TestConnectionStringViaAppSetting(string a }; return data; } + public async Task ValidateAsync(string connStr, string clientId = null) + { + throw new NotImplementedException(); + } + public async Task IsValidAsync(string connStr) + { + throw new NotImplementedException(); + } } } diff --git a/DiagnosticsExtension/Models/ConnectionStringValidator/QueueStorageValidator.cs b/DiagnosticsExtension/Models/ConnectionStringValidator/QueueStorageValidator.cs index f1f24182..7d9e5224 100644 --- a/DiagnosticsExtension/Models/ConnectionStringValidator/QueueStorageValidator.cs +++ b/DiagnosticsExtension/Models/ConnectionStringValidator/QueueStorageValidator.cs @@ -50,26 +50,26 @@ public async Task ValidateViaAppsettingAsync(s } else if (e.Message.Contains("managedidentitymissed")) { - response.Status = ConnectionStringValidationResult.ResultStatus.managedidentitymissed; + response.Status = ConnectionStringValidationResult.ResultStatus.Managedidentitymissed; } else if (e.Message.Contains("Unauthorized") || e.Message.Contains("AuthorizationPermissionMismatch")) { if (identityType == ConnectionStringValidationResult.ManagedIdentityType.User) { - response.Status = ConnectionStringValidationResult.ResultStatus.userAssignedmanagedidentity; + response.Status = ConnectionStringValidationResult.ResultStatus.UserAssignedmanagedidentity; } else { - response.Status = ConnectionStringValidationResult.ResultStatus.systemAssignedmanagedidentity; + response.Status = ConnectionStringValidationResult.ResultStatus.SystemAssignedmanagedidentity; } } else if (e.Message.Contains("ManagedIdentityCredential")) { - response.Status = ConnectionStringValidationResult.ResultStatus.managedIdentityCredential; + response.Status = ConnectionStringValidationResult.ResultStatus.ManagedIdentityCredential; } else if (e.Message.Contains("fullyQualifiedNamespacemissed")) { - response.Status = ConnectionStringValidationResult.ResultStatus.fullyQualifiedNamespacemissed; + response.Status = ConnectionStringValidationResult.ResultStatus.FullyQualifiedNamespacemissed; } else if (e is EmptyConnectionStringException) { diff --git a/DiagnosticsExtension/Models/ConnectionStringValidator/ServiceBusValidator.cs b/DiagnosticsExtension/Models/ConnectionStringValidator/ServiceBusValidator.cs index db1712ef..69341e0b 100644 --- a/DiagnosticsExtension/Models/ConnectionStringValidator/ServiceBusValidator.cs +++ b/DiagnosticsExtension/Models/ConnectionStringValidator/ServiceBusValidator.cs @@ -22,19 +22,19 @@ public class ServiceBusValidator : IConnectionStringValidator public string ProviderName => "Microsoft.Azure.ServiceBus"; public ConnectionStringType Type => ConnectionStringType.ServiceBus; - public Azure.Messaging.ServiceBus.ServiceBusReceiveMode ReceiveMode { get; set; } + ConnectionStringValidationResult.ManagedIdentityType identityType; - public async Task IsValidAsync(string connectionString) + public Task IsValidAsync(string connectionString) { try { - new ServiceBusClient(connectionString); + new ServiceBusConnectionStringBuilder(connectionString); } catch (Exception) { - return false; + return Task.FromResult(false); } - return true; + return Task.FromResult(true); } async public Task ValidateAsync(string connectionString, string clientId = null) @@ -101,12 +101,10 @@ protected async Task TestConnectionStringAsync(string connec { throw new EmptyConnectionStringException(); } - - ServiceBusClient client = null; + ServiceBusConnectionStringBuilder connectionStringBuilder = null; try { - client = new ServiceBusClient(connectionString); - + connectionStringBuilder = new ServiceBusConnectionStringBuilder(connectionString); } catch (Exception e) { @@ -119,11 +117,8 @@ protected async Task TestConnectionStringAsync(string connec Succeeded = true }; - ServiceBusSessionProcessorOptions opt = new ServiceBusSessionProcessorOptions(); - opt.ReceiveMode = ServiceBusReceiveMode.PeekLock; - string entityPath = ServiceBusConnectionStringProperties.Parse(connectionString).EntityPath; - ServiceBusReceiver receiver = client.CreateReceiver(entityPath); - ServiceBusReceivedMessage receivedMessage = await receiver.PeekMessageAsync(); + MessageReceiver msgReceiver = new MessageReceiver(connectionStringBuilder, ReceiveMode.PeekLock, prefetchCount: 1); + Message msg = await msgReceiver.PeekAsync(); return data; } @@ -151,26 +146,26 @@ async public Task ValidateViaAppsettingAsync(s } else if (e.Message.Contains("managedidentitymissed")) { - response.Status = ConnectionStringValidationResult.ResultStatus.managedidentitymissed; + response.Status = ConnectionStringValidationResult.ResultStatus.Managedidentitymissed; } else if (e.Message.Contains("Unauthorized")) { if (identityType == ConnectionStringValidationResult.ManagedIdentityType.User) { - response.Status = ConnectionStringValidationResult.ResultStatus.userAssignedmanagedidentity; + response.Status = ConnectionStringValidationResult.ResultStatus.UserAssignedmanagedidentity; } else { - response.Status = ConnectionStringValidationResult.ResultStatus.systemAssignedmanagedidentity; + response.Status = ConnectionStringValidationResult.ResultStatus.SystemAssignedmanagedidentity; } } else if (e.Message.Contains("ManagedIdentityCredential")) { - response.Status = ConnectionStringValidationResult.ResultStatus.managedIdentityCredential; + response.Status = ConnectionStringValidationResult.ResultStatus.ManagedIdentityCredential; } else if (e.Message.Contains("fullyQualifiedNamespacemissed")) { - response.Status = ConnectionStringValidationResult.ResultStatus.fullyQualifiedNamespacemissed; + response.Status = ConnectionStringValidationResult.ResultStatus.FullyQualifiedNamespacemissed; } else if (e is EmptyConnectionStringException) { From fd98f9810d4f3f53fc956bde8604e30bfba994a3 Mon Sep 17 00:00:00 2001 From: Gajibilli Koteswara Rao Date: Thu, 17 Feb 2022 23:25:53 +0530 Subject: [PATCH 03/26] changed the code as per the comments --- .../DiagnosticsExtension.csproj | 134 ++++-------------- .../BlobStorageValidator.cs | 101 +++---------- .../ConnectionStringType.cs | 4 +- .../ConnectionStringValidationResult.cs | 8 +- .../EventHubsValidator.cs | 39 +++-- .../ConnectionStringResponseUtility.cs | 79 +++++++++++ .../QueueStorageValidator.cs | 45 +++--- .../ServiceBusValidator.cs | 39 +++-- DiagnosticsExtension/Web.config | 12 +- DiagnosticsExtension/packages.config | 50 ++----- 10 files changed, 204 insertions(+), 307 deletions(-) create mode 100644 DiagnosticsExtension/Models/ConnectionStringValidator/Exceptions/ConnectionStringResponseUtility.cs diff --git a/DiagnosticsExtension/DiagnosticsExtension.csproj b/DiagnosticsExtension/DiagnosticsExtension.csproj index ef5739ce..873eb60d 100644 --- a/DiagnosticsExtension/DiagnosticsExtension.csproj +++ b/DiagnosticsExtension/DiagnosticsExtension.csproj @@ -56,14 +56,14 @@ ..\packages\Antlr.3.5.0.2\lib\Antlr3.Runtime.dll - - ..\packages\Azure.Core.1.21.0\lib\net461\Azure.Core.dll + + ..\packages\Azure.Core.1.22.0\lib\net461\Azure.Core.dll ..\packages\Azure.Core.Amqp.1.2.0\lib\netstandard2.0\Azure.Core.Amqp.dll - - ..\packages\Azure.Identity.1.4.0\lib\netstandard2.0\Azure.Identity.dll + + ..\packages\Azure.Identity.1.5.0\lib\netstandard2.0\Azure.Identity.dll ..\packages\Azure.Messaging.EventHubs.5.6.2\lib\netstandard2.0\Azure.Messaging.EventHubs.dll @@ -71,11 +71,11 @@ ..\packages\Azure.Messaging.EventHubs.Processor.5.6.2\lib\netstandard2.0\Azure.Messaging.EventHubs.Processor.dll - - ..\packages\Azure.Messaging.ServiceBus.7.5.1\lib\netstandard2.0\Azure.Messaging.ServiceBus.dll + + ..\packages\Azure.Messaging.ServiceBus.7.6.0\lib\netstandard2.0\Azure.Messaging.ServiceBus.dll - - ..\packages\Azure.Storage.Blobs.12.8.0\lib\netstandard2.0\Azure.Storage.Blobs.dll + + ..\packages\Azure.Storage.Blobs.12.10.0\lib\netstandard2.0\Azure.Storage.Blobs.dll ..\packages\Azure.Storage.Common.12.9.0\lib\netstandard2.0\Azure.Storage.Common.dll @@ -93,7 +93,7 @@ ..\packages\EntityFramework.6.2.0\lib\net45\EntityFramework.SqlServer.dll - ..\packages\Microsoft.Azure.Amqp.2.5.6\lib\net45\Microsoft.Azure.Amqp.dll + ..\packages\Microsoft.Azure.Amqp.2.5.10\lib\net45\Microsoft.Azure.Amqp.dll ..\packages\Microsoft.Azure.EventHubs.3.0.0\lib\net461\Microsoft.Azure.EventHubs.dll @@ -110,23 +110,8 @@ ..\packages\Microsoft.Azure.Services.AppAuthentication.1.0.3\lib\net452\Microsoft.Azure.Services.AppAuthentication.dll - - ..\packages\Microsoft.Azure.Storage.Blob.11.2.3\lib\net452\Microsoft.Azure.Storage.Blob.dll - - - ..\packages\Microsoft.Azure.Storage.Common.11.2.3\lib\net452\Microsoft.Azure.Storage.Common.dll - - - ..\packages\Microsoft.Azure.WebJobs.Core.3.0.30\lib\netstandard2.0\Microsoft.Azure.WebJobs.dll - - - ..\packages\Microsoft.Azure.WebJobs.Extensions.ServiceBus.5.2.0\lib\netstandard2.0\Microsoft.Azure.WebJobs.Extensions.ServiceBus.dll - - - ..\packages\Microsoft.Azure.WebJobs.3.0.30\lib\netstandard2.0\Microsoft.Azure.WebJobs.Host.dll - - ..\packages\Microsoft.Bcl.AsyncInterfaces.1.0.0\lib\net461\Microsoft.Bcl.AsyncInterfaces.dll + ..\packages\Microsoft.Bcl.AsyncInterfaces.1.1.1\lib\net461\Microsoft.Bcl.AsyncInterfaces.dll @@ -138,66 +123,6 @@ ..\packages\Microsoft.Data.Services.Client.5.8.4\lib\net40\Microsoft.Data.Services.Client.dll - - ..\packages\Microsoft.Extensions.Azure.1.1.1\lib\netstandard2.0\Microsoft.Extensions.Azure.dll - - - ..\packages\Microsoft.Extensions.Configuration.2.1.1\lib\netstandard2.0\Microsoft.Extensions.Configuration.dll - - - ..\packages\Microsoft.Extensions.Configuration.Abstractions.2.1.1\lib\netstandard2.0\Microsoft.Extensions.Configuration.Abstractions.dll - - - ..\packages\Microsoft.Extensions.Configuration.Binder.2.1.1\lib\netstandard2.0\Microsoft.Extensions.Configuration.Binder.dll - - - ..\packages\Microsoft.Extensions.Configuration.EnvironmentVariables.2.1.0\lib\netstandard2.0\Microsoft.Extensions.Configuration.EnvironmentVariables.dll - - - ..\packages\Microsoft.Extensions.Configuration.FileExtensions.2.1.0\lib\netstandard2.0\Microsoft.Extensions.Configuration.FileExtensions.dll - - - ..\packages\Microsoft.Extensions.Configuration.Json.2.1.0\lib\netstandard2.0\Microsoft.Extensions.Configuration.Json.dll - - - ..\packages\Microsoft.Extensions.DependencyInjection.2.1.0\lib\net461\Microsoft.Extensions.DependencyInjection.dll - - - ..\packages\Microsoft.Extensions.DependencyInjection.Abstractions.2.1.1\lib\netstandard2.0\Microsoft.Extensions.DependencyInjection.Abstractions.dll - - - ..\packages\Microsoft.Extensions.FileProviders.Abstractions.2.1.0\lib\netstandard2.0\Microsoft.Extensions.FileProviders.Abstractions.dll - - - ..\packages\Microsoft.Extensions.FileProviders.Physical.2.1.0\lib\netstandard2.0\Microsoft.Extensions.FileProviders.Physical.dll - - - ..\packages\Microsoft.Extensions.FileSystemGlobbing.2.1.0\lib\netstandard2.0\Microsoft.Extensions.FileSystemGlobbing.dll - - - ..\packages\Microsoft.Extensions.Hosting.2.1.0\lib\netstandard2.0\Microsoft.Extensions.Hosting.dll - - - ..\packages\Microsoft.Extensions.Hosting.Abstractions.2.1.0\lib\netstandard2.0\Microsoft.Extensions.Hosting.Abstractions.dll - - - ..\packages\Microsoft.Extensions.Logging.2.1.1\lib\netstandard2.0\Microsoft.Extensions.Logging.dll - - - ..\packages\Microsoft.Extensions.Logging.Abstractions.2.1.1\lib\netstandard2.0\Microsoft.Extensions.Logging.Abstractions.dll - - - ..\packages\Microsoft.Extensions.Logging.Configuration.2.1.0\lib\netstandard2.0\Microsoft.Extensions.Logging.Configuration.dll - - - ..\packages\Microsoft.Extensions.Options.2.1.1\lib\netstandard2.0\Microsoft.Extensions.Options.dll - - - ..\packages\Microsoft.Extensions.Options.ConfigurationExtensions.2.1.0\lib\netstandard2.0\Microsoft.Extensions.Options.ConfigurationExtensions.dll - - - ..\packages\Microsoft.Extensions.Primitives.2.1.1\lib\netstandard2.0\Microsoft.Extensions.Primitives.dll - ..\packages\Microsoft.Identity.Client.4.30.1\lib\net461\Microsoft.Identity.Client.dll @@ -245,9 +170,6 @@ ..\packages\System.Buffers.4.5.1\lib\net461\System.Buffers.dll - - ..\packages\System.ComponentModel.Annotations.4.4.0\lib\net461\System.ComponentModel.Annotations.dll - @@ -258,11 +180,6 @@ ..\packages\System.Diagnostics.DiagnosticSource.4.6.0\lib\net46\System.Diagnostics.DiagnosticSource.dll - - ..\packages\System.Diagnostics.TraceSource.4.3.0\lib\net46\System.Diagnostics.TraceSource.dll - True - True - @@ -279,8 +196,9 @@ ..\packages\System.Memory.Data.1.0.2\lib\net461\System.Memory.Data.dll - - ..\packages\System.Net.Http.4.3.3\lib\net46\System.Net.Http.dll + + ..\packages\System.Net.Http.4.3.4\lib\net46\System.Net.Http.dll + True True @@ -311,8 +229,13 @@ ..\packages\System.Runtime.4.3.0\lib\net462\System.Runtime.dll True - - ..\packages\System.Runtime.CompilerServices.Unsafe.4.6.0\lib\netstandard2.0\System.Runtime.CompilerServices.Unsafe.dll + + ..\packages\System.Runtime.CompilerServices.Unsafe.4.7.1\lib\net461\System.Runtime.CompilerServices.Unsafe.dll + + + ..\packages\System.Runtime.InteropServices.RuntimeInformation.4.3.0\lib\net45\System.Runtime.InteropServices.RuntimeInformation.dll + True + True @@ -345,15 +268,12 @@ ..\packages\System.Text.Encodings.Web.4.7.2\lib\net461\System.Text.Encodings.Web.dll - - ..\packages\System.Text.Json.4.6.0\lib\net461\System.Text.Json.dll + + ..\packages\System.Text.Json.4.7.2\lib\net461\System.Text.Json.dll ..\packages\System.Threading.Channels.4.6.0\lib\netstandard2.0\System.Threading.Channels.dll - - ..\packages\System.Threading.Tasks.Dataflow.4.8.0\lib\netstandard2.0\System.Threading.Tasks.Dataflow.dll - ..\packages\System.Threading.Tasks.Extensions.4.5.4\lib\net461\System.Threading.Tasks.Extensions.dll @@ -461,19 +381,21 @@ - + - + + + + - @@ -533,7 +455,7 @@ - + DiagnosticAnalysis\%(RecursiveDir)%(Filename)%(Extension) PreserveNewest diff --git a/DiagnosticsExtension/Models/ConnectionStringValidator/BlobStorageValidator.cs b/DiagnosticsExtension/Models/ConnectionStringValidator/BlobStorageValidator.cs index 2637e589..d6ea33ba 100644 --- a/DiagnosticsExtension/Models/ConnectionStringValidator/BlobStorageValidator.cs +++ b/DiagnosticsExtension/Models/ConnectionStringValidator/BlobStorageValidator.cs @@ -26,6 +26,8 @@ public class BlobStorageValidator : IConnectionStringValidator ConnectionStringValidationResult.ManagedIdentityType identityType; + private const string ManagedIdentity = "managedIdentityCredentialMissing"; + public async Task ValidateViaAppsettingAsync(string appsettingname, string entityName) { var response = new ConnectionStringValidationResult(Type); @@ -44,58 +46,7 @@ public async Task ValidateViaAppsettingAsync(s } catch (Exception e) { - if (e is MalformedConnectionStringException) - { - response.Status = ConnectionStringValidationResult.ResultStatus.MalformedConnectionString; - } - else if (e.Message.Contains("managedidentitymissed")) - { - response.Status = ConnectionStringValidationResult.ResultStatus.Managedidentitymissed; - } - else if (e.Message.Contains("Unauthorized") || e.Message.Contains("AuthorizationPermissionMismatch")) - { - if (identityType == ConnectionStringValidationResult.ManagedIdentityType.User) - { - response.Status = ConnectionStringValidationResult.ResultStatus.UserAssignedmanagedidentity; - } - else - { - response.Status = ConnectionStringValidationResult.ResultStatus.SystemAssignedmanagedidentity; - } - } - else if (e.Message.Contains("ManagedIdentityCredential")) - { - response.Status = ConnectionStringValidationResult.ResultStatus.ManagedIdentityCredential; - } - else if (e.Message.Contains("fullyQualifiedNamespacemissed")) - { - response.Status = ConnectionStringValidationResult.ResultStatus.FullyQualifiedNamespacemissed; - } - else if (e is EmptyConnectionStringException) - { - response.Status = ConnectionStringValidationResult.ResultStatus.EmptyConnectionString; - } - else if (e.InnerException != null && - e.InnerException.Message.Contains("The remote name could not be resolved")) - { - response.Status = ConnectionStringValidationResult.ResultStatus.DnsLookupFailed; - } - else if (e is StorageException) - { - if (((StorageException)e).RequestInformation.HttpStatusCode == 401) - { - response.Status = ConnectionStringValidationResult.ResultStatus.AuthFailure; - } - else if (((StorageException)e).RequestInformation.HttpStatusCode == 403) - { - response.Status = ConnectionStringValidationResult.ResultStatus.Forbidden; - } - } - else - { - response.Status = ConnectionStringValidationResult.ResultStatus.UnknownError; - } - response.Exception = e; + response = ConnectionStringResponseUtility.EvaluateResponseStatus(e, Type, identityType); } return response; @@ -104,16 +55,15 @@ public async Task ValidateViaAppsettingAsync(s public async Task TestConnectionStringViaAppSetting(string appSettingName, string entityName) { var envDict = Environment.GetEnvironmentVariables(); - string appSettingClientIdValue, appSettingClientCredValue = null; - string value = null; + string appSettingClientIdValue, appSettingClientCredValue = null; BlobServiceClient client = null; if (envDict.Contains(appSettingName)) { try { - value = Environment.GetEnvironmentVariable(appSettingName); - client = new BlobServiceClient(value); + string connectionString = Environment.GetEnvironmentVariable(appSettingName); + client = new BlobServiceClient(connectionString); } catch (ArgumentNullException e) { @@ -128,40 +78,33 @@ public async Task TestConnectionStringViaAppSetting(string a { try { - - - value = Environment.GetEnvironmentVariable(appSettingName + "__blobServiceUri"); - if (string.IsNullOrEmpty(value)) + string serviceUriString = Environment.GetEnvironmentVariable(appSettingName + "__blobServiceUri"); + if (string.IsNullOrEmpty(serviceUriString)) { - value = Environment.GetEnvironmentVariable(appSettingName + "__serviceUri"); + serviceUriString = Environment.GetEnvironmentVariable(appSettingName + "__serviceUri"); } - if (!string.IsNullOrEmpty(value)) + appSettingClientIdValue = Environment.GetEnvironmentVariable(appSettingName + "__clientId"); + appSettingClientCredValue = Environment.GetEnvironmentVariable(appSettingName + "__credential"); + Uri serviceUri = new Uri(serviceUriString); + // User assigned managed identity detected + if (!string.IsNullOrEmpty(appSettingClientIdValue)) { - appSettingClientIdValue = Environment.GetEnvironmentVariable(appSettingName + "__clientId"); - appSettingClientCredValue = Environment.GetEnvironmentVariable(appSettingName + "__credential"); - Uri objuri = new Uri(value); - if (!string.IsNullOrEmpty(appSettingClientIdValue)) + if (appSettingClientCredValue != "managedidentity") { - if (appSettingClientCredValue != "managedidentity") - { - throw new ManagedIdentityException("managedidentitymissed"); - } - else - { - identityType = ConnectionStringValidationResult.ManagedIdentityType.User; - client = new BlobServiceClient(objuri, new Azure.Identity.ManagedIdentityCredential(appSettingClientIdValue)); - } + throw new ManagedIdentityException(ManagedIdentity); } else { - identityType = ConnectionStringValidationResult.ManagedIdentityType.System; - client = new BlobServiceClient(objuri, new Azure.Identity.ManagedIdentityCredential()); + identityType = ConnectionStringValidationResult.ManagedIdentityType.User; + client = new BlobServiceClient(serviceUri, new Azure.Identity.ManagedIdentityCredential(appSettingClientIdValue)); } } + // System assigned managed identity detected else { - throw new ManagedIdentityException("fullyQualifiedNamespacemissed"); - } + identityType = ConnectionStringValidationResult.ManagedIdentityType.System; + client = new BlobServiceClient(serviceUri, new Azure.Identity.ManagedIdentityCredential()); + } } catch (Exception e) { diff --git a/DiagnosticsExtension/Models/ConnectionStringValidator/ConnectionStringType.cs b/DiagnosticsExtension/Models/ConnectionStringValidator/ConnectionStringType.cs index 40c58d53..ea1be897 100644 --- a/DiagnosticsExtension/Models/ConnectionStringValidator/ConnectionStringType.cs +++ b/DiagnosticsExtension/Models/ConnectionStringValidator/ConnectionStringType.cs @@ -19,11 +19,11 @@ public enum ConnectionStringType KeyVault, Http, RedisCache, - StorageAccount, ServiceBus, EventHubs, + StorageAccount, BlobStorageAccount, QueueStorageAccount, FileShareStorageAccount, - } + } } diff --git a/DiagnosticsExtension/Models/ConnectionStringValidator/ConnectionStringValidationResult.cs b/DiagnosticsExtension/Models/ConnectionStringValidator/ConnectionStringValidationResult.cs index fa8c0684..49eb655c 100644 --- a/DiagnosticsExtension/Models/ConnectionStringValidator/ConnectionStringValidationResult.cs +++ b/DiagnosticsExtension/Models/ConnectionStringValidator/ConnectionStringValidationResult.cs @@ -41,10 +41,10 @@ public enum ResultStatus EmptyConnectionString, MalformedConnectionString, UnknownError, - Managedidentitymissed, - FullyQualifiedNamespacemissed, - SystemAssignedmanagedidentity, - UserAssignedmanagedidentity, + ManagedIdentityCredentialMissing, + FullyQualifiedNamespaceMissed, + SystemAssignedManagedIdentity, + UserAssignedManagedIdentity, ManagedIdentityCredential } public enum ManagedIdentityType diff --git a/DiagnosticsExtension/Models/ConnectionStringValidator/EventHubsValidator.cs b/DiagnosticsExtension/Models/ConnectionStringValidator/EventHubsValidator.cs index c801f806..275303fe 100644 --- a/DiagnosticsExtension/Models/ConnectionStringValidator/EventHubsValidator.cs +++ b/DiagnosticsExtension/Models/ConnectionStringValidator/EventHubsValidator.cs @@ -128,26 +128,26 @@ async public Task ValidateViaAppsettingAsync(s } else if (e.Message.Contains("managedidentitymissed")) { - response.Status = ConnectionStringValidationResult.ResultStatus.Managedidentitymissed; + response.Status = ConnectionStringValidationResult.ResultStatus.ManagedIdentityCredentialMissing; } else if (e.Message.Contains("Unauthorized") || e.Message.Contains("unauthorized")) { if (identityType == ConnectionStringValidationResult.ManagedIdentityType.User) { - response.Status = ConnectionStringValidationResult.ResultStatus.UserAssignedmanagedidentity; + response.Status = ConnectionStringValidationResult.ResultStatus.UserAssignedManagedIdentity; } else { - response.Status = ConnectionStringValidationResult.ResultStatus.SystemAssignedmanagedidentity; + response.Status = ConnectionStringValidationResult.ResultStatus.SystemAssignedManagedIdentity; } } else if (e.Message.Contains("ManagedIdentityCredential")) { response.Status = ConnectionStringValidationResult.ResultStatus.ManagedIdentityCredential; } - else if (e.Message.Contains("fullyQualifiedNamespacemissed")) + else if (e.Message.Contains("fullyQualifiedNamespace")) { - response.Status = ConnectionStringValidationResult.ResultStatus.FullyQualifiedNamespacemissed; + response.Status = ConnectionStringValidationResult.ResultStatus.FullyQualifiedNamespaceMissed; } else if (e is EmptyConnectionStringException) { @@ -204,33 +204,26 @@ protected async Task TestConnectionStringViaAppSettingAsync( { try { - value = Environment.GetEnvironmentVariable(appSettingName + "__fullyQualifiedNamespace"); - if (!string.IsNullOrEmpty(value)) + value = Environment.GetEnvironmentVariable(appSettingName + "__fullyQualifiedNamespace"); + appSettingClientIdValue = Environment.GetEnvironmentVariable(appSettingName + "__clientId"); + appSettingClientCredValue = Environment.GetEnvironmentVariable(appSettingName + "__credential"); + if (!string.IsNullOrEmpty(appSettingClientIdValue)) { - appSettingClientIdValue = Environment.GetEnvironmentVariable(appSettingName + "__clientId"); - appSettingClientCredValue = Environment.GetEnvironmentVariable(appSettingName + "__credential"); - if (!string.IsNullOrEmpty(appSettingClientIdValue)) + if (appSettingClientCredValue != "managedidentity") { - if (appSettingClientCredValue != "managedidentity") - { - throw new ManagedIdentityException("managedidentitymissed"); - } - else - { - identityType = ConnectionStringValidationResult.ManagedIdentityType.User; - client = new EventHubProducerClient(value, eventHubName, new ManagedIdentityCredential(appSettingClientIdValue)); - } + throw new ManagedIdentityException("managedidentitymissed"); } else { - identityType = ConnectionStringValidationResult.ManagedIdentityType.System; - client = new EventHubProducerClient(value, eventHubName, new ManagedIdentityCredential()); + identityType = ConnectionStringValidationResult.ManagedIdentityType.User; + client = new EventHubProducerClient(value, eventHubName, new ManagedIdentityCredential(appSettingClientIdValue)); } } else { - throw new ManagedIdentityException("fullyQualifiedNamespacemissed"); - } + identityType = ConnectionStringValidationResult.ManagedIdentityType.System; + client = new EventHubProducerClient(value, eventHubName, new ManagedIdentityCredential()); + } } catch (Exception e) { diff --git a/DiagnosticsExtension/Models/ConnectionStringValidator/Exceptions/ConnectionStringResponseUtility.cs b/DiagnosticsExtension/Models/ConnectionStringValidator/Exceptions/ConnectionStringResponseUtility.cs new file mode 100644 index 00000000..a255f606 --- /dev/null +++ b/DiagnosticsExtension/Models/ConnectionStringValidator/Exceptions/ConnectionStringResponseUtility.cs @@ -0,0 +1,79 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. +// +// ----------------------------------------------------------------------- + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Web; +using Microsoft.WindowsAzure.Storage; + +namespace DiagnosticsExtension.Models.ConnectionStringValidator.Exceptions +{ + public static class ConnectionStringResponseUtility + { + public static ConnectionStringValidationResult EvaluateResponseStatus(Exception e, ConnectionStringType type, ConnectionStringValidationResult.ManagedIdentityType identityType) + { + + var response = new ConnectionStringValidationResult(type); + + if (e is MalformedConnectionStringException) + { + response.Status = ConnectionStringValidationResult.ResultStatus.MalformedConnectionString; + } + else if (e.Message.Contains("managedIdentityCredentialMissing")) + { + response.Status = ConnectionStringValidationResult.ResultStatus.ManagedIdentityCredentialMissing; + } + else if (e.Message.Contains("Unauthorized") || e.Message.Contains("AuthorizationPermissionMismatch")) + { + if (identityType == ConnectionStringValidationResult.ManagedIdentityType.User) + { + response.Status = ConnectionStringValidationResult.ResultStatus.UserAssignedManagedIdentity; + } + else + { + response.Status = ConnectionStringValidationResult.ResultStatus.SystemAssignedManagedIdentity; + } + } + else if (e.Message.Contains("ManagedIdentityCredential")) + { + response.Status = ConnectionStringValidationResult.ResultStatus.ManagedIdentityCredential; + } + else if (e.Message.Contains("fullyQualifiedNamespace")) + { + response.Status = ConnectionStringValidationResult.ResultStatus.FullyQualifiedNamespaceMissed; + } + else if (e is EmptyConnectionStringException) + { + response.Status = ConnectionStringValidationResult.ResultStatus.EmptyConnectionString; + } + else if (e.InnerException != null && + e.InnerException.Message.Contains("The remote name could not be resolved")) + { + response.Status = ConnectionStringValidationResult.ResultStatus.DnsLookupFailed; + } + else if (e is StorageException) + { + if (((StorageException)e).RequestInformation.HttpStatusCode == 401) + { + response.Status = ConnectionStringValidationResult.ResultStatus.AuthFailure; + } + else if (((StorageException)e).RequestInformation.HttpStatusCode == 403) + { + response.Status = ConnectionStringValidationResult.ResultStatus.Forbidden; + } + } + else + { + response.Status = ConnectionStringValidationResult.ResultStatus.UnknownError; + } + response.Exception = e; + + return response; + } + } +} diff --git a/DiagnosticsExtension/Models/ConnectionStringValidator/QueueStorageValidator.cs b/DiagnosticsExtension/Models/ConnectionStringValidator/QueueStorageValidator.cs index 7d9e5224..11f6ab79 100644 --- a/DiagnosticsExtension/Models/ConnectionStringValidator/QueueStorageValidator.cs +++ b/DiagnosticsExtension/Models/ConnectionStringValidator/QueueStorageValidator.cs @@ -50,26 +50,26 @@ public async Task ValidateViaAppsettingAsync(s } else if (e.Message.Contains("managedidentitymissed")) { - response.Status = ConnectionStringValidationResult.ResultStatus.Managedidentitymissed; + response.Status = ConnectionStringValidationResult.ResultStatus.ManagedIdentityCredentialMissing; } else if (e.Message.Contains("Unauthorized") || e.Message.Contains("AuthorizationPermissionMismatch")) { if (identityType == ConnectionStringValidationResult.ManagedIdentityType.User) { - response.Status = ConnectionStringValidationResult.ResultStatus.UserAssignedmanagedidentity; + response.Status = ConnectionStringValidationResult.ResultStatus.UserAssignedManagedIdentity; } else { - response.Status = ConnectionStringValidationResult.ResultStatus.SystemAssignedmanagedidentity; + response.Status = ConnectionStringValidationResult.ResultStatus.SystemAssignedManagedIdentity; } } else if (e.Message.Contains("ManagedIdentityCredential")) { response.Status = ConnectionStringValidationResult.ResultStatus.ManagedIdentityCredential; } - else if (e.Message.Contains("fullyQualifiedNamespacemissed")) + else if (e.Message.Contains("fullyQualifiedNamespace")) { - response.Status = ConnectionStringValidationResult.ResultStatus.FullyQualifiedNamespacemissed; + response.Status = ConnectionStringValidationResult.ResultStatus.FullyQualifiedNamespaceMissed; } else if (e is EmptyConnectionStringException) { @@ -123,42 +123,31 @@ public async Task TestConnectionStringViaAppSetting(string a { throw new MalformedConnectionStringException(e.Message, e); } - } else { try { - - - value = Environment.GetEnvironmentVariable(appSettingName + "__queueServiceUri"); - if (!string.IsNullOrEmpty(value)) + value = Environment.GetEnvironmentVariable(appSettingName + "__queueServiceUri"); + appSettingClientIdValue = Environment.GetEnvironmentVariable(appSettingName + "__clientId"); + appSettingClientCredValue = Environment.GetEnvironmentVariable(appSettingName + "__credential"); + Uri objuri = new Uri(value); + if (!string.IsNullOrEmpty(appSettingClientIdValue)) { - appSettingClientIdValue = Environment.GetEnvironmentVariable(appSettingName + "__clientId"); - appSettingClientCredValue = Environment.GetEnvironmentVariable(appSettingName + "__credential"); - Uri objuri = new Uri(value); - if (!string.IsNullOrEmpty(appSettingClientIdValue)) + if (appSettingClientCredValue != "managedidentity") { - if (appSettingClientCredValue != "managedidentity") - { - throw new ManagedIdentityException("managedidentitymissed"); - } - else - { - identityType = ConnectionStringValidationResult.ManagedIdentityType.User; - client = new QueueServiceClient(objuri, new Azure.Identity.ManagedIdentityCredential(appSettingClientIdValue)); - } - + throw new ManagedIdentityException("managedidentitymissed"); } else { - identityType = ConnectionStringValidationResult.ManagedIdentityType.System; - client = new QueueServiceClient(objuri, new Azure.Identity.ManagedIdentityCredential()); + identityType = ConnectionStringValidationResult.ManagedIdentityType.User; + client = new QueueServiceClient(objuri, new Azure.Identity.ManagedIdentityCredential(appSettingClientIdValue)); } } else { - throw new ManagedIdentityException("fullyQualifiedNamespacemissed"); + identityType = ConnectionStringValidationResult.ManagedIdentityType.System; + client = new QueueServiceClient(objuri, new Azure.Identity.ManagedIdentityCredential()); } } catch (Exception e) @@ -178,8 +167,6 @@ public async Task TestConnectionStringViaAppSetting(string a } } - - TestConnectionData data = new TestConnectionData { ConnectionString = client.ToString(), diff --git a/DiagnosticsExtension/Models/ConnectionStringValidator/ServiceBusValidator.cs b/DiagnosticsExtension/Models/ConnectionStringValidator/ServiceBusValidator.cs index 69341e0b..9fdc23fa 100644 --- a/DiagnosticsExtension/Models/ConnectionStringValidator/ServiceBusValidator.cs +++ b/DiagnosticsExtension/Models/ConnectionStringValidator/ServiceBusValidator.cs @@ -146,26 +146,26 @@ async public Task ValidateViaAppsettingAsync(s } else if (e.Message.Contains("managedidentitymissed")) { - response.Status = ConnectionStringValidationResult.ResultStatus.Managedidentitymissed; + response.Status = ConnectionStringValidationResult.ResultStatus.ManagedIdentityCredentialMissing; } else if (e.Message.Contains("Unauthorized")) { if (identityType == ConnectionStringValidationResult.ManagedIdentityType.User) { - response.Status = ConnectionStringValidationResult.ResultStatus.UserAssignedmanagedidentity; + response.Status = ConnectionStringValidationResult.ResultStatus.UserAssignedManagedIdentity; } else { - response.Status = ConnectionStringValidationResult.ResultStatus.SystemAssignedmanagedidentity; + response.Status = ConnectionStringValidationResult.ResultStatus.SystemAssignedManagedIdentity; } } else if (e.Message.Contains("ManagedIdentityCredential")) { response.Status = ConnectionStringValidationResult.ResultStatus.ManagedIdentityCredential; } - else if (e.Message.Contains("fullyQualifiedNamespacemissed")) + else if (e.Message.Contains("fullyQualifiedNamespace")) { - response.Status = ConnectionStringValidationResult.ResultStatus.FullyQualifiedNamespacemissed; + response.Status = ConnectionStringValidationResult.ResultStatus.FullyQualifiedNamespaceMissed; } else if (e is EmptyConnectionStringException) { @@ -226,34 +226,27 @@ protected async Task TestConnectionStringViaAppSettingAsync( { try { - value = Environment.GetEnvironmentVariable(appSettingName + "__fullyQualifiedNamespace"); - if (!string.IsNullOrEmpty(value)) + value = Environment.GetEnvironmentVariable(appSettingName + "__fullyQualifiedNamespace"); + appSettingClientIdValue = Environment.GetEnvironmentVariable(appSettingName + "__clientId"); + appSettingClientCredValue = Environment.GetEnvironmentVariable(appSettingName + "__credential"); + if (!string.IsNullOrEmpty(appSettingClientIdValue)) { - appSettingClientIdValue = Environment.GetEnvironmentVariable(appSettingName + "__clientId"); - appSettingClientCredValue = Environment.GetEnvironmentVariable(appSettingName + "__credential"); - if (!string.IsNullOrEmpty(appSettingClientIdValue)) + if (appSettingClientCredValue != "managedidentity") { - if (appSettingClientCredValue != "managedidentity") - { - throw new ManagedIdentityException("managedidentitymissed"); - } - else - { - identityType = ConnectionStringValidationResult.ManagedIdentityType.User; - client = new ServiceBusClient(value, new Azure.Identity.ManagedIdentityCredential(appSettingClientIdValue)); - } + throw new ManagedIdentityException("managedidentitymissed"); } else { - identityType = ConnectionStringValidationResult.ManagedIdentityType.System; - client = new ServiceBusClient(value, new Azure.Identity.ManagedIdentityCredential()); + identityType = ConnectionStringValidationResult.ManagedIdentityType.User; + client = new ServiceBusClient(value, new Azure.Identity.ManagedIdentityCredential(appSettingClientIdValue)); } } else { - throw new ManagedIdentityException("fullyQualifiedNamespacemissed"); - } + identityType = ConnectionStringValidationResult.ManagedIdentityType.System; + client = new ServiceBusClient(value, new Azure.Identity.ManagedIdentityCredential()); + } } catch (Exception e) { diff --git a/DiagnosticsExtension/Web.config b/DiagnosticsExtension/Web.config index fa13fbc4..3adcc5bf 100644 --- a/DiagnosticsExtension/Web.config +++ b/DiagnosticsExtension/Web.config @@ -122,7 +122,7 @@ - + @@ -182,7 +182,7 @@ - + @@ -192,6 +192,14 @@ + + + + + + + + diff --git a/DiagnosticsExtension/packages.config b/DiagnosticsExtension/packages.config index 955d5b08..96369727 100644 --- a/DiagnosticsExtension/packages.config +++ b/DiagnosticsExtension/packages.config @@ -1,13 +1,13 @@  - + - + - - + + @@ -28,44 +28,18 @@ - + - - - - - - - + - - - - - - - - - - - - - - - - - - - - @@ -75,7 +49,7 @@ - + @@ -85,21 +59,20 @@ - - - + - + + @@ -108,9 +81,8 @@ - + - From 2c880c7b37ba738f1500aa156c1f59cc364ec5d4 Mon Sep 17 00:00:00 2001 From: Gajibilli Koteswara Rao Date: Fri, 25 Feb 2022 23:31:04 +0530 Subject: [PATCH 04/26] Changes done as per the sid's comments in PR --- .../DiagnosticsExtension.csproj | 4 +- .../BlobStorageValidator.cs | 38 +++--- .../ConnectionStringValidationResult.cs | 3 +- .../EventHubsValidator.cs | 112 ++-------------- .../ConnectionStringResponseUtility.cs | 53 +++++++- .../FileShareStorageValidator.cs | 32 +---- .../QueueStorageValidator.cs | 89 ++++--------- .../ServiceBusValidator.cs | 120 ++---------------- DiagnosticsExtension/packages.config | 2 +- 9 files changed, 130 insertions(+), 323 deletions(-) diff --git a/DiagnosticsExtension/DiagnosticsExtension.csproj b/DiagnosticsExtension/DiagnosticsExtension.csproj index 873eb60d..4e16c0f3 100644 --- a/DiagnosticsExtension/DiagnosticsExtension.csproj +++ b/DiagnosticsExtension/DiagnosticsExtension.csproj @@ -62,8 +62,8 @@ ..\packages\Azure.Core.Amqp.1.2.0\lib\netstandard2.0\Azure.Core.Amqp.dll - - ..\packages\Azure.Identity.1.5.0\lib\netstandard2.0\Azure.Identity.dll + + ..\packages\Azure.Identity.1.4.0\lib\netstandard2.0\Azure.Identity.dll ..\packages\Azure.Messaging.EventHubs.5.6.2\lib\netstandard2.0\Azure.Messaging.EventHubs.dll diff --git a/DiagnosticsExtension/Models/ConnectionStringValidator/BlobStorageValidator.cs b/DiagnosticsExtension/Models/ConnectionStringValidator/BlobStorageValidator.cs index d6ea33ba..6ac661f0 100644 --- a/DiagnosticsExtension/Models/ConnectionStringValidator/BlobStorageValidator.cs +++ b/DiagnosticsExtension/Models/ConnectionStringValidator/BlobStorageValidator.cs @@ -25,9 +25,6 @@ public class BlobStorageValidator : IConnectionStringValidator public ConnectionStringType Type => ConnectionStringType.BlobStorageAccount; ConnectionStringValidationResult.ManagedIdentityType identityType; - - private const string ManagedIdentity = "managedIdentityCredentialMissing"; - public async Task ValidateViaAppsettingAsync(string appsettingname, string entityName) { var response = new ConnectionStringValidationResult(Type); @@ -55,7 +52,7 @@ public async Task ValidateViaAppsettingAsync(s public async Task TestConnectionStringViaAppSetting(string appSettingName, string entityName) { var envDict = Environment.GetEnvironmentVariables(); - string appSettingClientIdValue, appSettingClientCredValue = null; + string appSettingClientIdValue, appSettingClientCredValue = null; BlobServiceClient client = null; if (envDict.Contains(appSettingName)) @@ -83,28 +80,35 @@ public async Task TestConnectionStringViaAppSetting(string a { serviceUriString = Environment.GetEnvironmentVariable(appSettingName + "__serviceUri"); } - appSettingClientIdValue = Environment.GetEnvironmentVariable(appSettingName + "__clientId"); - appSettingClientCredValue = Environment.GetEnvironmentVariable(appSettingName + "__credential"); - Uri serviceUri = new Uri(serviceUriString); - // User assigned managed identity detected - if (!string.IsNullOrEmpty(appSettingClientIdValue)) + if (!string.IsNullOrEmpty(serviceUriString)) { - if (appSettingClientCredValue != "managedidentity") + appSettingClientIdValue = Environment.GetEnvironmentVariable(appSettingName + ConnectionStringResponseUtility.ClientId); + appSettingClientCredValue = Environment.GetEnvironmentVariable(appSettingName + ConnectionStringResponseUtility.Credential); + Uri serviceUri = new Uri(serviceUriString); + // Creating client using User assigned managed identity + if (!string.IsNullOrEmpty(appSettingClientIdValue)) { - throw new ManagedIdentityException(ManagedIdentity); + if (appSettingClientCredValue != ConnectionStringResponseUtility.ValidCredentialValue) + { + throw new ManagedIdentityException(ConnectionStringResponseUtility.ManagedIdentityCredentialMissing); + } + else + { + identityType = ConnectionStringValidationResult.ManagedIdentityType.User; + client = new BlobServiceClient(serviceUri, new Azure.Identity.ManagedIdentityCredential(appSettingClientIdValue)); + } } + // Creating client using System assigned managed identity else { - identityType = ConnectionStringValidationResult.ManagedIdentityType.User; - client = new BlobServiceClient(serviceUri, new Azure.Identity.ManagedIdentityCredential(appSettingClientIdValue)); + identityType = ConnectionStringValidationResult.ManagedIdentityType.System; + client = new BlobServiceClient(serviceUri, new Azure.Identity.ManagedIdentityCredential()); } } - // System assigned managed identity detected else { - identityType = ConnectionStringValidationResult.ManagedIdentityType.System; - client = new BlobServiceClient(serviceUri, new Azure.Identity.ManagedIdentityCredential()); - } + throw new ManagedIdentityException(ConnectionStringResponseUtility.ServiceUriMissed); + } } catch (Exception e) { diff --git a/DiagnosticsExtension/Models/ConnectionStringValidator/ConnectionStringValidationResult.cs b/DiagnosticsExtension/Models/ConnectionStringValidator/ConnectionStringValidationResult.cs index 49eb655c..10dfb286 100644 --- a/DiagnosticsExtension/Models/ConnectionStringValidator/ConnectionStringValidationResult.cs +++ b/DiagnosticsExtension/Models/ConnectionStringValidator/ConnectionStringValidationResult.cs @@ -45,7 +45,8 @@ public enum ResultStatus FullyQualifiedNamespaceMissed, SystemAssignedManagedIdentity, UserAssignedManagedIdentity, - ManagedIdentityCredential + ManagedIdentityCredential, + ServiceUriMissed } public enum ManagedIdentityType { diff --git a/DiagnosticsExtension/Models/ConnectionStringValidator/EventHubsValidator.cs b/DiagnosticsExtension/Models/ConnectionStringValidator/EventHubsValidator.cs index 275303fe..ef049fbe 100644 --- a/DiagnosticsExtension/Models/ConnectionStringValidator/EventHubsValidator.cs +++ b/DiagnosticsExtension/Models/ConnectionStringValidator/EventHubsValidator.cs @@ -20,8 +20,8 @@ public class EventHubsValidator : IConnectionStringValidator public string ProviderName => "Microsoft.Azure.EventHubs"; public ConnectionStringType Type => ConnectionStringType.EventHubs; - ConnectionStringValidationResult.ManagedIdentityType identityType; + ConnectionStringValidationResult.ManagedIdentityType identityType; public Task IsValidAsync(string connectionString) { try @@ -53,37 +53,7 @@ async public Task ValidateAsync(string connect } catch (Exception e) { - if (e is MalformedConnectionStringException) - { - response.Status = ConnectionStringValidationResult.ResultStatus.MalformedConnectionString; - } - else if (e is EmptyConnectionStringException) - { - response.Status = ConnectionStringValidationResult.ResultStatus.EmptyConnectionString; - } - else if (e is ArgumentNullException || - e.Message.Contains("could not be found") || - e.Message.Contains("was not found")) - { - response.Status = ConnectionStringValidationResult.ResultStatus.MalformedConnectionString; - } - else if (e.Message.Contains("No such host is known")) - { - response.Status = ConnectionStringValidationResult.ResultStatus.DnsLookupFailed; - } - else if (e.Message.Contains("InvalidSignature")) - { - response.Status = ConnectionStringValidationResult.ResultStatus.AuthFailure; - } - else if (e.Message.Contains("Ip has been prevented to connect to the endpoint")) - { - response.Status = ConnectionStringValidationResult.ResultStatus.Forbidden; - } - else - { - response.Status = ConnectionStringValidationResult.ResultStatus.UnknownError; - } - response.Exception = e; + response = ConnectionStringResponseUtility.EvaluateResponseStatus(e, Type, identityType); } return response; @@ -122,68 +92,14 @@ async public Task ValidateViaAppsettingAsync(s } catch (Exception e) { - if (e is MalformedConnectionStringException) - { - response.Status = ConnectionStringValidationResult.ResultStatus.MalformedConnectionString; - } - else if (e.Message.Contains("managedidentitymissed")) - { - response.Status = ConnectionStringValidationResult.ResultStatus.ManagedIdentityCredentialMissing; - } - else if (e.Message.Contains("Unauthorized") || e.Message.Contains("unauthorized")) - { - if (identityType == ConnectionStringValidationResult.ManagedIdentityType.User) - { - response.Status = ConnectionStringValidationResult.ResultStatus.UserAssignedManagedIdentity; - } - else - { - response.Status = ConnectionStringValidationResult.ResultStatus.SystemAssignedManagedIdentity; - } - } - else if (e.Message.Contains("ManagedIdentityCredential")) - { - response.Status = ConnectionStringValidationResult.ResultStatus.ManagedIdentityCredential; - } - else if (e.Message.Contains("fullyQualifiedNamespace")) - { - response.Status = ConnectionStringValidationResult.ResultStatus.FullyQualifiedNamespaceMissed; - } - else if (e is EmptyConnectionStringException) - { - response.Status = ConnectionStringValidationResult.ResultStatus.EmptyConnectionString; - } - else if (e is ArgumentNullException || - e.Message.Contains("could not be found") || - e.Message.Contains("was not found")) - { - response.Status = ConnectionStringValidationResult.ResultStatus.MalformedConnectionString; - } - else if (e.Message.Contains("No such host is known")) - { - response.Status = ConnectionStringValidationResult.ResultStatus.DnsLookupFailed; - } - else if (e.Message.Contains("InvalidSignature") || - e.Message.Contains("Unauthorized")) - { - response.Status = ConnectionStringValidationResult.ResultStatus.AuthFailure; - } - else if (e.Message.Contains("Ip has been prevented to connect to the endpoint")) - { - response.Status = ConnectionStringValidationResult.ResultStatus.Forbidden; - } - else - { - response.Status = ConnectionStringValidationResult.ResultStatus.UnknownError; - } - response.Exception = e; + response = ConnectionStringResponseUtility.EvaluateResponseStatus(e, Type, identityType); } return response; } protected async Task TestConnectionStringViaAppSettingAsync(string appSettingName, string entityName) { - string value, appSettingClientIdValue, appSettingClientCredValue = ""; + string appSettingClientIdValue, appSettingClientCredValue = ""; EventHubProducerClient client = null; var envDict = Environment.GetEnvironmentVariables(); string eventHubName = entityName; @@ -192,8 +108,8 @@ protected async Task TestConnectionStringViaAppSettingAsync( { try { - value = Environment.GetEnvironmentVariable(appSettingName); - client = new EventHubProducerClient(value); + string connectionString = Environment.GetEnvironmentVariable(appSettingName); + client = new EventHubProducerClient(connectionString); } catch (Exception e) { @@ -204,26 +120,26 @@ protected async Task TestConnectionStringViaAppSettingAsync( { try { - value = Environment.GetEnvironmentVariable(appSettingName + "__fullyQualifiedNamespace"); - appSettingClientIdValue = Environment.GetEnvironmentVariable(appSettingName + "__clientId"); - appSettingClientCredValue = Environment.GetEnvironmentVariable(appSettingName + "__credential"); + string serviceUriString = Environment.GetEnvironmentVariable(appSettingName + ConnectionStringResponseUtility.FullyQualifiedNamespace); + appSettingClientIdValue = Environment.GetEnvironmentVariable(appSettingName + ConnectionStringResponseUtility.ClientId); + appSettingClientCredValue = Environment.GetEnvironmentVariable(appSettingName + ConnectionStringResponseUtility.Credential); if (!string.IsNullOrEmpty(appSettingClientIdValue)) { - if (appSettingClientCredValue != "managedidentity") + if (appSettingClientCredValue != ConnectionStringResponseUtility.ValidCredentialValue) { - throw new ManagedIdentityException("managedidentitymissed"); + throw new ManagedIdentityException(ConnectionStringResponseUtility.ManagedIdentityCredentialMissing); } else { identityType = ConnectionStringValidationResult.ManagedIdentityType.User; - client = new EventHubProducerClient(value, eventHubName, new ManagedIdentityCredential(appSettingClientIdValue)); + client = new EventHubProducerClient(serviceUriString, eventHubName, new ManagedIdentityCredential(appSettingClientIdValue)); } } else { identityType = ConnectionStringValidationResult.ManagedIdentityType.System; - client = new EventHubProducerClient(value, eventHubName, new ManagedIdentityCredential()); - } + client = new EventHubProducerClient(serviceUriString, eventHubName, new ManagedIdentityCredential()); + } } catch (Exception e) { diff --git a/DiagnosticsExtension/Models/ConnectionStringValidator/Exceptions/ConnectionStringResponseUtility.cs b/DiagnosticsExtension/Models/ConnectionStringValidator/Exceptions/ConnectionStringResponseUtility.cs index a255f606..fef4f512 100644 --- a/DiagnosticsExtension/Models/ConnectionStringValidator/Exceptions/ConnectionStringResponseUtility.cs +++ b/DiagnosticsExtension/Models/ConnectionStringValidator/Exceptions/ConnectionStringResponseUtility.cs @@ -15,11 +15,18 @@ namespace DiagnosticsExtension.Models.ConnectionStringValidator.Exceptions { public static class ConnectionStringResponseUtility { + #region string constants for network validator + public const string ClientId = "__clientId"; + public const string Credential = "__credential"; + public const string ServiceUriMissed = "ServiceUriMissed"; + public const string ValidCredentialValue = "managedidentity"; + public const string FullyQualifiedNamespace = "__fullyQualifiedNamespace"; + public const string ManagedIdentityCredentialMissing = "ManagedIdentityCredentialMissing"; + #endregion + public static ConnectionStringValidationResult EvaluateResponseStatus(Exception e, ConnectionStringType type, ConnectionStringValidationResult.ManagedIdentityType identityType) { - var response = new ConnectionStringValidationResult(type); - if (e is MalformedConnectionStringException) { response.Status = ConnectionStringValidationResult.ResultStatus.MalformedConnectionString; @@ -47,6 +54,10 @@ public static ConnectionStringValidationResult EvaluateResponseStatus(Exception { response.Status = ConnectionStringValidationResult.ResultStatus.FullyQualifiedNamespaceMissed; } + else if (e.Message.Contains("ServiceUriMissed")) + { + response.Status = ConnectionStringValidationResult.ResultStatus.ServiceUriMissed; + } else if (e is EmptyConnectionStringException) { response.Status = ConnectionStringValidationResult.ResultStatus.EmptyConnectionString; @@ -56,6 +67,44 @@ public static ConnectionStringValidationResult EvaluateResponseStatus(Exception { response.Status = ConnectionStringValidationResult.ResultStatus.DnsLookupFailed; } + else if (e.InnerException != null && e.InnerException.InnerException != null && + e.InnerException.InnerException.Message.Contains("The remote name could not be resolved")) + { + response.Status = ConnectionStringValidationResult.ResultStatus.DnsLookupFailed; + } + else if (e.Message.Contains("No such host is known")) + { + response.Status = ConnectionStringValidationResult.ResultStatus.DnsLookupFailed; + } + else if (e is ArgumentNullException || + e.Message.Contains("could not be found") || + e.Message.Contains("was not found")) + { + response.Status = ConnectionStringValidationResult.ResultStatus.MalformedConnectionString; + } + else if (e is ArgumentException && e.Message.Contains("entityPath is null") || + e.Message.Contains("HostNotFound") || + e.Message.Contains("could not be found") || + e.Message.Contains("The argument is null or white space")) + { + response.Status = ConnectionStringValidationResult.ResultStatus.MalformedConnectionString; + } + else if (e.Message.Contains("InvalidSignature") || + e.Message.Contains("Unauthorized")) + { + response.Status = ConnectionStringValidationResult.ResultStatus.AuthFailure; + } + else if ((e is ArgumentException && e.Message.Contains("Authentication ")) || + e.Message.Contains("claim is empty or token is invalid") || + e.Message.Contains("InvalidSignature") || + e.Message.Contains("Unauthorized")) + { + response.Status = ConnectionStringValidationResult.ResultStatus.AuthFailure; + } + else if (e.Message.Contains("Ip has been prevented to connect to the endpoint")) + { + response.Status = ConnectionStringValidationResult.ResultStatus.Forbidden; + } else if (e is StorageException) { if (((StorageException)e).RequestInformation.HttpStatusCode == 401) diff --git a/DiagnosticsExtension/Models/ConnectionStringValidator/FileShareStorageValidator.cs b/DiagnosticsExtension/Models/ConnectionStringValidator/FileShareStorageValidator.cs index 6033fca2..7bda9883 100644 --- a/DiagnosticsExtension/Models/ConnectionStringValidator/FileShareStorageValidator.cs +++ b/DiagnosticsExtension/Models/ConnectionStringValidator/FileShareStorageValidator.cs @@ -24,6 +24,8 @@ public class FileShareStorageValidator : IConnectionStringValidator public string ProviderName => "Microsoft.WindowsAzure.Storage"; public ConnectionStringType Type => ConnectionStringType.FileShareStorageAccount; + + ConnectionStringValidationResult.ManagedIdentityType identityType; public async Task ValidateViaAppsettingAsync(string appsettingname, string entityName) { var response = new ConnectionStringValidationResult(Type); @@ -42,35 +44,7 @@ public async Task ValidateViaAppsettingAsync(s } catch (Exception e) { - if (e is MalformedConnectionStringException) - { - response.Status = ConnectionStringValidationResult.ResultStatus.MalformedConnectionString; - } - else if (e is EmptyConnectionStringException) - { - response.Status = ConnectionStringValidationResult.ResultStatus.EmptyConnectionString; - } - else if (e.InnerException != null && - e.InnerException.Message.Contains("The remote name could not be resolved")) - { - response.Status = ConnectionStringValidationResult.ResultStatus.DnsLookupFailed; - } - else if (e is StorageException) - { - if (((StorageException)e).RequestInformation.HttpStatusCode == 401) - { - response.Status = ConnectionStringValidationResult.ResultStatus.AuthFailure; - } - else if (((StorageException)e).RequestInformation.HttpStatusCode == 403) - { - response.Status = ConnectionStringValidationResult.ResultStatus.Forbidden; - } - } - else - { - response.Status = ConnectionStringValidationResult.ResultStatus.UnknownError; - } - response.Exception = e; + response = ConnectionStringResponseUtility.EvaluateResponseStatus(e, Type, identityType); } return response; diff --git a/DiagnosticsExtension/Models/ConnectionStringValidator/QueueStorageValidator.cs b/DiagnosticsExtension/Models/ConnectionStringValidator/QueueStorageValidator.cs index 11f6ab79..bca90fdf 100644 --- a/DiagnosticsExtension/Models/ConnectionStringValidator/QueueStorageValidator.cs +++ b/DiagnosticsExtension/Models/ConnectionStringValidator/QueueStorageValidator.cs @@ -24,8 +24,8 @@ public class QueueStorageValidator : IConnectionStringValidator public string ProviderName => "Microsoft.WindowsAzure.Storage"; public ConnectionStringType Type => ConnectionStringType.QueueStorageAccount; - ConnectionStringValidationResult.ManagedIdentityType identityType; + ConnectionStringValidationResult.ManagedIdentityType identityType; public async Task ValidateViaAppsettingAsync(string appsettingname, string entityName) { var response = new ConnectionStringValidationResult(Type); @@ -44,58 +44,7 @@ public async Task ValidateViaAppsettingAsync(s } catch (Exception e) { - if (e is MalformedConnectionStringException) - { - response.Status = ConnectionStringValidationResult.ResultStatus.MalformedConnectionString; - } - else if (e.Message.Contains("managedidentitymissed")) - { - response.Status = ConnectionStringValidationResult.ResultStatus.ManagedIdentityCredentialMissing; - } - else if (e.Message.Contains("Unauthorized") || e.Message.Contains("AuthorizationPermissionMismatch")) - { - if (identityType == ConnectionStringValidationResult.ManagedIdentityType.User) - { - response.Status = ConnectionStringValidationResult.ResultStatus.UserAssignedManagedIdentity; - } - else - { - response.Status = ConnectionStringValidationResult.ResultStatus.SystemAssignedManagedIdentity; - } - } - else if (e.Message.Contains("ManagedIdentityCredential")) - { - response.Status = ConnectionStringValidationResult.ResultStatus.ManagedIdentityCredential; - } - else if (e.Message.Contains("fullyQualifiedNamespace")) - { - response.Status = ConnectionStringValidationResult.ResultStatus.FullyQualifiedNamespaceMissed; - } - else if (e is EmptyConnectionStringException) - { - response.Status = ConnectionStringValidationResult.ResultStatus.EmptyConnectionString; - } - else if (e.InnerException != null && - e.InnerException.Message.Contains("The remote name could not be resolved")) - { - response.Status = ConnectionStringValidationResult.ResultStatus.DnsLookupFailed; - } - else if (e is StorageException) - { - if (((StorageException)e).RequestInformation.HttpStatusCode == 401) - { - response.Status = ConnectionStringValidationResult.ResultStatus.AuthFailure; - } - else if (((StorageException)e).RequestInformation.HttpStatusCode == 403) - { - response.Status = ConnectionStringValidationResult.ResultStatus.Forbidden; - } - } - else - { - response.Status = ConnectionStringValidationResult.ResultStatus.UnknownError; - } - response.Exception = e; + response = ConnectionStringResponseUtility.EvaluateResponseStatus(e, Type, identityType); } return response; @@ -105,15 +54,14 @@ public async Task TestConnectionStringViaAppSetting(string a { var envDict = Environment.GetEnvironmentVariables(); string appSettingClientIdValue, appSettingClientCredValue = null; - string value = null; QueueServiceClient client = null; if (envDict.Contains(appSettingName)) { try { - value = Environment.GetEnvironmentVariable(appSettingName); - client = new QueueServiceClient(value); + string connectionString = Environment.GetEnvironmentVariable(appSettingName); + client = new QueueServiceClient(connectionString); } catch (ArgumentNullException e) { @@ -128,26 +76,33 @@ public async Task TestConnectionStringViaAppSetting(string a { try { - value = Environment.GetEnvironmentVariable(appSettingName + "__queueServiceUri"); - appSettingClientIdValue = Environment.GetEnvironmentVariable(appSettingName + "__clientId"); - appSettingClientCredValue = Environment.GetEnvironmentVariable(appSettingName + "__credential"); - Uri objuri = new Uri(value); - if (!string.IsNullOrEmpty(appSettingClientIdValue)) + string serviceUriString = Environment.GetEnvironmentVariable(appSettingName + "__queueServiceUri"); + if (!string.IsNullOrEmpty(serviceUriString)) { - if (appSettingClientCredValue != "managedidentity") + appSettingClientIdValue = Environment.GetEnvironmentVariable(appSettingName + ConnectionStringResponseUtility.ClientId); + appSettingClientCredValue = Environment.GetEnvironmentVariable(appSettingName + ConnectionStringResponseUtility.Credential); + Uri serviceUri = new Uri(serviceUriString); + if (!string.IsNullOrEmpty(appSettingClientIdValue)) { - throw new ManagedIdentityException("managedidentitymissed"); + if (appSettingClientCredValue != ConnectionStringResponseUtility.ValidCredentialValue) + { + throw new ManagedIdentityException(ConnectionStringResponseUtility.ManagedIdentityCredentialMissing); + } + else + { + identityType = ConnectionStringValidationResult.ManagedIdentityType.User; + client = new QueueServiceClient(serviceUri, new Azure.Identity.ManagedIdentityCredential(appSettingClientIdValue)); + } } else { - identityType = ConnectionStringValidationResult.ManagedIdentityType.User; - client = new QueueServiceClient(objuri, new Azure.Identity.ManagedIdentityCredential(appSettingClientIdValue)); + identityType = ConnectionStringValidationResult.ManagedIdentityType.System; + client = new QueueServiceClient(serviceUri, new Azure.Identity.ManagedIdentityCredential()); } } else { - identityType = ConnectionStringValidationResult.ManagedIdentityType.System; - client = new QueueServiceClient(objuri, new Azure.Identity.ManagedIdentityCredential()); + throw new ManagedIdentityException(ConnectionStringResponseUtility.ServiceUriMissed); } } catch (Exception e) diff --git a/DiagnosticsExtension/Models/ConnectionStringValidator/ServiceBusValidator.cs b/DiagnosticsExtension/Models/ConnectionStringValidator/ServiceBusValidator.cs index 9fdc23fa..2d5923bc 100644 --- a/DiagnosticsExtension/Models/ConnectionStringValidator/ServiceBusValidator.cs +++ b/DiagnosticsExtension/Models/ConnectionStringValidator/ServiceBusValidator.cs @@ -22,7 +22,7 @@ public class ServiceBusValidator : IConnectionStringValidator public string ProviderName => "Microsoft.Azure.ServiceBus"; public ConnectionStringType Type => ConnectionStringType.ServiceBus; - + ConnectionStringValidationResult.ManagedIdentityType identityType; public Task IsValidAsync(string connectionString) { @@ -55,41 +55,7 @@ async public Task ValidateAsync(string connect } catch (Exception e) { - if (e is MalformedConnectionStringException || e is ArgumentNullException) - { - response.Status = ConnectionStringValidationResult.ResultStatus.MalformedConnectionString; - } - else if (e is EmptyConnectionStringException) - { - response.Status = ConnectionStringValidationResult.ResultStatus.EmptyConnectionString; - } - else if ((e is ArgumentException && e.Message.Contains("Authentication ")) || - e.Message.Contains("claim is empty or token is invalid") || - e.Message.Contains("InvalidSignature")) - { - response.Status = ConnectionStringValidationResult.ResultStatus.AuthFailure; - } - else if (e is ArgumentException && e.Message.Contains("entityPath is null") || - e.Message.Contains("HostNotFound") || - e.Message.Contains("could not be found") || - e.Message.Contains("The argument is null or white space")) - { - response.Status = ConnectionStringValidationResult.ResultStatus.MalformedConnectionString; - } - else if (e.InnerException != null && e.InnerException.InnerException != null && - e.InnerException.InnerException.Message.Contains("The remote name could not be resolved")) - { - response.Status = ConnectionStringValidationResult.ResultStatus.DnsLookupFailed; - } - else if (e.Message.Contains("Ip has been prevented to connect to the endpoint")) - { - response.Status = ConnectionStringValidationResult.ResultStatus.Forbidden; - } - else - { - response.Status = ConnectionStringValidationResult.ResultStatus.UnknownError; - } - response.Exception = e; + response = ConnectionStringResponseUtility.EvaluateResponseStatus(e, Type, identityType); } return response; @@ -140,72 +106,14 @@ async public Task ValidateViaAppsettingAsync(s } catch (Exception e) { - if (e is MalformedConnectionStringException || e is ArgumentNullException) - { - response.Status = ConnectionStringValidationResult.ResultStatus.MalformedConnectionString; - } - else if (e.Message.Contains("managedidentitymissed")) - { - response.Status = ConnectionStringValidationResult.ResultStatus.ManagedIdentityCredentialMissing; - } - else if (e.Message.Contains("Unauthorized")) - { - if (identityType == ConnectionStringValidationResult.ManagedIdentityType.User) - { - response.Status = ConnectionStringValidationResult.ResultStatus.UserAssignedManagedIdentity; - } - else - { - response.Status = ConnectionStringValidationResult.ResultStatus.SystemAssignedManagedIdentity; - } - } - else if (e.Message.Contains("ManagedIdentityCredential")) - { - response.Status = ConnectionStringValidationResult.ResultStatus.ManagedIdentityCredential; - } - else if (e.Message.Contains("fullyQualifiedNamespace")) - { - response.Status = ConnectionStringValidationResult.ResultStatus.FullyQualifiedNamespaceMissed; - } - else if (e is EmptyConnectionStringException) - { - response.Status = ConnectionStringValidationResult.ResultStatus.EmptyConnectionString; - } - else if ((e is ArgumentException && e.Message.Contains("Authentication ")) || - e.Message.Contains("claim is empty or token is invalid") || - e.Message.Contains("InvalidSignature") || - e.Message.Contains("Unauthorized")) - { - response.Status = ConnectionStringValidationResult.ResultStatus.AuthFailure; - } - else if (e is ArgumentException && e.Message.Contains("entityPath is null") || - e.Message.Contains("HostNotFound") || - e.Message.Contains("could not be found") || - e.Message.Contains("The argument is null or white space")) - { - response.Status = ConnectionStringValidationResult.ResultStatus.MalformedConnectionString; - } - else if (e.InnerException != null && e.InnerException.InnerException != null && - e.InnerException.InnerException.Message.Contains("The remote name could not be resolved")) - { - response.Status = ConnectionStringValidationResult.ResultStatus.DnsLookupFailed; - } - else if (e.Message.Contains("Ip has been prevented to connect to the endpoint")) - { - response.Status = ConnectionStringValidationResult.ResultStatus.Forbidden; - } - else - { - response.Status = ConnectionStringValidationResult.ResultStatus.UnknownError; - } - response.Exception = e; + response = ConnectionStringResponseUtility.EvaluateResponseStatus(e, Type, identityType); } return response; } protected async Task TestConnectionStringViaAppSettingAsync(string appSettingName, string entityName) { - string value, appSettingClientIdValue, appSettingClientCredValue = ""; + string appSettingClientIdValue, appSettingClientCredValue = ""; ServiceBusClient client = null; var envDict = Environment.GetEnvironmentVariables(); @@ -213,8 +121,8 @@ protected async Task TestConnectionStringViaAppSettingAsync( { try { - value = Environment.GetEnvironmentVariable(appSettingName); - client = new ServiceBusClient(value); + string connectionString = Environment.GetEnvironmentVariable(appSettingName); + client = new ServiceBusClient(connectionString); } catch (Exception e) { @@ -226,27 +134,27 @@ protected async Task TestConnectionStringViaAppSettingAsync( { try { - value = Environment.GetEnvironmentVariable(appSettingName + "__fullyQualifiedNamespace"); - appSettingClientIdValue = Environment.GetEnvironmentVariable(appSettingName + "__clientId"); - appSettingClientCredValue = Environment.GetEnvironmentVariable(appSettingName + "__credential"); + string serviceUriString = Environment.GetEnvironmentVariable(appSettingName + ConnectionStringResponseUtility.FullyQualifiedNamespace); + appSettingClientIdValue = Environment.GetEnvironmentVariable(appSettingName + ConnectionStringResponseUtility.ClientId); + appSettingClientCredValue = Environment.GetEnvironmentVariable(appSettingName + ConnectionStringResponseUtility.Credential); if (!string.IsNullOrEmpty(appSettingClientIdValue)) { - if (appSettingClientCredValue != "managedidentity") + if (appSettingClientCredValue != ConnectionStringResponseUtility.ValidCredentialValue) { - throw new ManagedIdentityException("managedidentitymissed"); + throw new ManagedIdentityException(ConnectionStringResponseUtility.ManagedIdentityCredentialMissing); } else { identityType = ConnectionStringValidationResult.ManagedIdentityType.User; - client = new ServiceBusClient(value, new Azure.Identity.ManagedIdentityCredential(appSettingClientIdValue)); + client = new ServiceBusClient(serviceUriString, new Azure.Identity.ManagedIdentityCredential(appSettingClientIdValue)); } } else { identityType = ConnectionStringValidationResult.ManagedIdentityType.System; - client = new ServiceBusClient(value, new Azure.Identity.ManagedIdentityCredential()); - } + client = new ServiceBusClient(serviceUriString, new Azure.Identity.ManagedIdentityCredential()); + } } catch (Exception e) { diff --git a/DiagnosticsExtension/packages.config b/DiagnosticsExtension/packages.config index 96369727..9d8610dc 100644 --- a/DiagnosticsExtension/packages.config +++ b/DiagnosticsExtension/packages.config @@ -3,7 +3,7 @@ - + From 973dad8198a751c07dcb68daba90dd707720cc38 Mon Sep 17 00:00:00 2001 From: Gajibilli Koteswara Rao Date: Fri, 25 Feb 2022 23:43:23 +0530 Subject: [PATCH 05/26] Added comments for queue, eventhub and servicebus --- .../Models/ConnectionStringValidator/EventHubsValidator.cs | 2 ++ .../Models/ConnectionStringValidator/QueueStorageValidator.cs | 2 ++ .../Models/ConnectionStringValidator/ServiceBusValidator.cs | 2 ++ 3 files changed, 6 insertions(+) diff --git a/DiagnosticsExtension/Models/ConnectionStringValidator/EventHubsValidator.cs b/DiagnosticsExtension/Models/ConnectionStringValidator/EventHubsValidator.cs index ef049fbe..63971058 100644 --- a/DiagnosticsExtension/Models/ConnectionStringValidator/EventHubsValidator.cs +++ b/DiagnosticsExtension/Models/ConnectionStringValidator/EventHubsValidator.cs @@ -123,6 +123,7 @@ protected async Task TestConnectionStringViaAppSettingAsync( string serviceUriString = Environment.GetEnvironmentVariable(appSettingName + ConnectionStringResponseUtility.FullyQualifiedNamespace); appSettingClientIdValue = Environment.GetEnvironmentVariable(appSettingName + ConnectionStringResponseUtility.ClientId); appSettingClientCredValue = Environment.GetEnvironmentVariable(appSettingName + ConnectionStringResponseUtility.Credential); + // Creating client using User assigned managed identity if (!string.IsNullOrEmpty(appSettingClientIdValue)) { if (appSettingClientCredValue != ConnectionStringResponseUtility.ValidCredentialValue) @@ -135,6 +136,7 @@ protected async Task TestConnectionStringViaAppSettingAsync( client = new EventHubProducerClient(serviceUriString, eventHubName, new ManagedIdentityCredential(appSettingClientIdValue)); } } + // Creating client using System assigned managed identity else { identityType = ConnectionStringValidationResult.ManagedIdentityType.System; diff --git a/DiagnosticsExtension/Models/ConnectionStringValidator/QueueStorageValidator.cs b/DiagnosticsExtension/Models/ConnectionStringValidator/QueueStorageValidator.cs index bca90fdf..9ee734c2 100644 --- a/DiagnosticsExtension/Models/ConnectionStringValidator/QueueStorageValidator.cs +++ b/DiagnosticsExtension/Models/ConnectionStringValidator/QueueStorageValidator.cs @@ -82,6 +82,7 @@ public async Task TestConnectionStringViaAppSetting(string a appSettingClientIdValue = Environment.GetEnvironmentVariable(appSettingName + ConnectionStringResponseUtility.ClientId); appSettingClientCredValue = Environment.GetEnvironmentVariable(appSettingName + ConnectionStringResponseUtility.Credential); Uri serviceUri = new Uri(serviceUriString); + // Creating client using User assigned managed identity if (!string.IsNullOrEmpty(appSettingClientIdValue)) { if (appSettingClientCredValue != ConnectionStringResponseUtility.ValidCredentialValue) @@ -94,6 +95,7 @@ public async Task TestConnectionStringViaAppSetting(string a client = new QueueServiceClient(serviceUri, new Azure.Identity.ManagedIdentityCredential(appSettingClientIdValue)); } } + // Creating client using System assigned managed identity else { identityType = ConnectionStringValidationResult.ManagedIdentityType.System; diff --git a/DiagnosticsExtension/Models/ConnectionStringValidator/ServiceBusValidator.cs b/DiagnosticsExtension/Models/ConnectionStringValidator/ServiceBusValidator.cs index 2d5923bc..89aba27e 100644 --- a/DiagnosticsExtension/Models/ConnectionStringValidator/ServiceBusValidator.cs +++ b/DiagnosticsExtension/Models/ConnectionStringValidator/ServiceBusValidator.cs @@ -137,6 +137,7 @@ protected async Task TestConnectionStringViaAppSettingAsync( string serviceUriString = Environment.GetEnvironmentVariable(appSettingName + ConnectionStringResponseUtility.FullyQualifiedNamespace); appSettingClientIdValue = Environment.GetEnvironmentVariable(appSettingName + ConnectionStringResponseUtility.ClientId); appSettingClientCredValue = Environment.GetEnvironmentVariable(appSettingName + ConnectionStringResponseUtility.Credential); + // Creating client using User assigned managed identity if (!string.IsNullOrEmpty(appSettingClientIdValue)) { if (appSettingClientCredValue != ConnectionStringResponseUtility.ValidCredentialValue) @@ -150,6 +151,7 @@ protected async Task TestConnectionStringViaAppSettingAsync( client = new ServiceBusClient(serviceUriString, new Azure.Identity.ManagedIdentityCredential(appSettingClientIdValue)); } } + // Creating client using System assigned managed identity else { identityType = ConnectionStringValidationResult.ManagedIdentityType.System; From 858dd6af43520381208fe8fdcb21f6f75722808a Mon Sep 17 00:00:00 2001 From: Gajibilli Koteswara Rao Date: Wed, 2 Mar 2022 22:07:53 +0530 Subject: [PATCH 06/26] Code has been changed as per the comments in PR --- .../BlobStorageValidator.cs | 59 ++++++++----------- .../ConnectionStringValidationResult.cs | 14 +++-- .../EventHubsValidator.cs | 17 +++--- .../ConnectionStringResponseUtility.cs | 53 ++++++++--------- .../FileShareStorageValidator.cs | 9 +-- .../QueueStorageValidator.cs | 51 +++++++--------- .../ServiceBusValidator.cs | 46 ++++++--------- 7 files changed, 106 insertions(+), 143 deletions(-) diff --git a/DiagnosticsExtension/Models/ConnectionStringValidator/BlobStorageValidator.cs b/DiagnosticsExtension/Models/ConnectionStringValidator/BlobStorageValidator.cs index 6ac661f0..c33375ae 100644 --- a/DiagnosticsExtension/Models/ConnectionStringValidator/BlobStorageValidator.cs +++ b/DiagnosticsExtension/Models/ConnectionStringValidator/BlobStorageValidator.cs @@ -21,17 +21,15 @@ namespace DiagnosticsExtension.Models.ConnectionStringValidator public class BlobStorageValidator : IConnectionStringValidator { public string ProviderName => "Microsoft.WindowsAzure.Storage"; - public ConnectionStringType Type => ConnectionStringType.BlobStorageAccount; - - ConnectionStringValidationResult.ManagedIdentityType identityType; + public ConnectionStringValidationResult response = null; public async Task ValidateViaAppsettingAsync(string appsettingname, string entityName) { - var response = new ConnectionStringValidationResult(Type); + response = new ConnectionStringValidationResult(Type); try { - var result = await TestConnectionStringViaAppSetting(appsettingname, entityName); + var result = await TestConnectionStringViaAppSettingAsync(appsettingname, entityName); if (result.Succeeded) { response.Status = ConnectionStringValidationResult.ResultStatus.Success; @@ -43,13 +41,13 @@ public async Task ValidateViaAppsettingAsync(s } catch (Exception e) { - response = ConnectionStringResponseUtility.EvaluateResponseStatus(e, Type, identityType); + ConnectionStringResponseUtility.EvaluateResponseStatus(e, Type, ref response); } return response; } - public async Task TestConnectionStringViaAppSetting(string appSettingName, string entityName) + public async Task TestConnectionStringViaAppSettingAsync(string appSettingName, string entityName) { var envDict = Environment.GetEnvironmentVariables(); string appSettingClientIdValue, appSettingClientCredValue = null; @@ -73,46 +71,39 @@ public async Task TestConnectionStringViaAppSetting(string a } else { - try + string serviceUriString = Environment.GetEnvironmentVariable(appSettingName + ConnectionStringResponseUtility.BlobServiceUri); + if (string.IsNullOrEmpty(serviceUriString)) { - string serviceUriString = Environment.GetEnvironmentVariable(appSettingName + "__blobServiceUri"); - if (string.IsNullOrEmpty(serviceUriString)) - { - serviceUriString = Environment.GetEnvironmentVariable(appSettingName + "__serviceUri"); - } - if (!string.IsNullOrEmpty(serviceUriString)) + serviceUriString = Environment.GetEnvironmentVariable(appSettingName + ConnectionStringResponseUtility.ServiceUri); + } + if (!string.IsNullOrEmpty(serviceUriString)) + { + appSettingClientIdValue = Environment.GetEnvironmentVariable(appSettingName + ConnectionStringResponseUtility.ClientId); + appSettingClientCredValue = Environment.GetEnvironmentVariable(appSettingName + ConnectionStringResponseUtility.Credential); + Uri serviceUri = new Uri(serviceUriString); + // Creating client using User assigned managed identity + if (!string.IsNullOrEmpty(appSettingClientIdValue)) { - appSettingClientIdValue = Environment.GetEnvironmentVariable(appSettingName + ConnectionStringResponseUtility.ClientId); - appSettingClientCredValue = Environment.GetEnvironmentVariable(appSettingName + ConnectionStringResponseUtility.Credential); - Uri serviceUri = new Uri(serviceUriString); - // Creating client using User assigned managed identity - if (!string.IsNullOrEmpty(appSettingClientIdValue)) + if (appSettingClientCredValue != ConnectionStringResponseUtility.ValidCredentialValue) { - if (appSettingClientCredValue != ConnectionStringResponseUtility.ValidCredentialValue) - { - throw new ManagedIdentityException(ConnectionStringResponseUtility.ManagedIdentityCredentialMissing); - } - else - { - identityType = ConnectionStringValidationResult.ManagedIdentityType.User; - client = new BlobServiceClient(serviceUri, new Azure.Identity.ManagedIdentityCredential(appSettingClientIdValue)); - } + throw new ManagedIdentityException(ConnectionStringResponseUtility.ManagedIdentityCredentialMissing); } - // Creating client using System assigned managed identity else { - identityType = ConnectionStringValidationResult.ManagedIdentityType.System; - client = new BlobServiceClient(serviceUri, new Azure.Identity.ManagedIdentityCredential()); + response.IdentityType = ConnectionStringResponseUtility.User; + client = new BlobServiceClient(serviceUri, new Azure.Identity.ManagedIdentityCredential(appSettingClientIdValue)); } } + // Creating client using System assigned managed identity else { - throw new ManagedIdentityException(ConnectionStringResponseUtility.ServiceUriMissed); + response.IdentityType = ConnectionStringResponseUtility.System; + client = new BlobServiceClient(serviceUri, new Azure.Identity.ManagedIdentityCredential()); } } - catch (Exception e) + else { - throw new ManagedIdentityException(e.Message, e); + throw new ManagedIdentityException(ConnectionStringResponseUtility.ServiceUriMissing); } } client.GetBlobContainersAsync(); diff --git a/DiagnosticsExtension/Models/ConnectionStringValidator/ConnectionStringValidationResult.cs b/DiagnosticsExtension/Models/ConnectionStringValidator/ConnectionStringValidationResult.cs index 10dfb286..dc96c3d8 100644 --- a/DiagnosticsExtension/Models/ConnectionStringValidator/ConnectionStringValidationResult.cs +++ b/DiagnosticsExtension/Models/ConnectionStringValidator/ConnectionStringValidationResult.cs @@ -16,6 +16,7 @@ namespace DiagnosticsExtension.Models.ConnectionStringValidator public class ConnectionStringValidationResult { public ResultStatus? Status; + public string IdentityType; public string StatusText => Status?.ToString(); public Exception Exception; public object Payload; @@ -40,13 +41,14 @@ public enum ResultStatus MsiFailure, EmptyConnectionString, MalformedConnectionString, - UnknownError, ManagedIdentityCredentialMissing, - FullyQualifiedNamespaceMissed, - SystemAssignedManagedIdentity, - UserAssignedManagedIdentity, - ManagedIdentityCredential, - ServiceUriMissed + FullyQualifiedNamespaceMissing, + SystemAssignedIdentityFailure, + UserAssignedIdentityFailure, + ManagedIdentityNotConfigured, + ManagedIdentityAuthFailure, + ServiceUriMissing, + UnknownError, } public enum ManagedIdentityType { diff --git a/DiagnosticsExtension/Models/ConnectionStringValidator/EventHubsValidator.cs b/DiagnosticsExtension/Models/ConnectionStringValidator/EventHubsValidator.cs index 63971058..8111aac1 100644 --- a/DiagnosticsExtension/Models/ConnectionStringValidator/EventHubsValidator.cs +++ b/DiagnosticsExtension/Models/ConnectionStringValidator/EventHubsValidator.cs @@ -18,10 +18,8 @@ namespace DiagnosticsExtension.Models.ConnectionStringValidator public class EventHubsValidator : IConnectionStringValidator { public string ProviderName => "Microsoft.Azure.EventHubs"; - public ConnectionStringType Type => ConnectionStringType.EventHubs; - - ConnectionStringValidationResult.ManagedIdentityType identityType; + public ConnectionStringValidationResult response = null; public Task IsValidAsync(string connectionString) { try @@ -37,7 +35,7 @@ public Task IsValidAsync(string connectionString) async public Task ValidateAsync(string connectionString, string clientId = null) { - var response = new ConnectionStringValidationResult(Type); + response = new ConnectionStringValidationResult(Type); try { @@ -53,7 +51,7 @@ async public Task ValidateAsync(string connect } catch (Exception e) { - response = ConnectionStringResponseUtility.EvaluateResponseStatus(e, Type, identityType); + ConnectionStringResponseUtility.EvaluateResponseStatus(e, Type, ref response); } return response; @@ -76,7 +74,7 @@ protected async Task TestConnectionStringAsync(string connec async public Task ValidateViaAppsettingAsync(string appsettingName, string entityName) { - var response = new ConnectionStringValidationResult(Type); + response = new ConnectionStringValidationResult(Type); try { @@ -92,7 +90,7 @@ async public Task ValidateViaAppsettingAsync(s } catch (Exception e) { - response = ConnectionStringResponseUtility.EvaluateResponseStatus(e, Type, identityType); + ConnectionStringResponseUtility.EvaluateResponseStatus(e, Type, ref response); } return response; @@ -132,14 +130,14 @@ protected async Task TestConnectionStringViaAppSettingAsync( } else { - identityType = ConnectionStringValidationResult.ManagedIdentityType.User; + response.IdentityType = ConnectionStringResponseUtility.User; client = new EventHubProducerClient(serviceUriString, eventHubName, new ManagedIdentityCredential(appSettingClientIdValue)); } } // Creating client using System assigned managed identity else { - identityType = ConnectionStringValidationResult.ManagedIdentityType.System; + response.IdentityType = ConnectionStringResponseUtility.System; client = new EventHubProducerClient(serviceUriString, eventHubName, new ManagedIdentityCredential()); } } @@ -147,7 +145,6 @@ protected async Task TestConnectionStringViaAppSettingAsync( { throw new ManagedIdentityException(e.Message, e); } - } await client.GetPartitionIdsAsync(); await client.CloseAsync(); diff --git a/DiagnosticsExtension/Models/ConnectionStringValidator/Exceptions/ConnectionStringResponseUtility.cs b/DiagnosticsExtension/Models/ConnectionStringValidator/Exceptions/ConnectionStringResponseUtility.cs index fef4f512..d53041ed 100644 --- a/DiagnosticsExtension/Models/ConnectionStringValidator/Exceptions/ConnectionStringResponseUtility.cs +++ b/DiagnosticsExtension/Models/ConnectionStringValidator/Exceptions/ConnectionStringResponseUtility.cs @@ -9,6 +9,8 @@ using System.Collections.Generic; using System.Linq; using System.Web; +using Azure; +using Azure.Identity; using Microsoft.WindowsAzure.Storage; namespace DiagnosticsExtension.Models.ConnectionStringValidator.Exceptions @@ -16,51 +18,48 @@ namespace DiagnosticsExtension.Models.ConnectionStringValidator.Exceptions public static class ConnectionStringResponseUtility { #region string constants for network validator + public const string User = "User"; + public const string System = "System"; public const string ClientId = "__clientId"; public const string Credential = "__credential"; - public const string ServiceUriMissed = "ServiceUriMissed"; + public const string ServiceUri = "__serviceUri"; + public const string BlobServiceUri = "__blobServiceUri"; + public const string ServiceUriMissing = "ServiceUriMissing"; + public const string QueueServiceUri = "__queueServiceUri"; public const string ValidCredentialValue = "managedidentity"; public const string FullyQualifiedNamespace = "__fullyQualifiedNamespace"; public const string ManagedIdentityCredentialMissing = "ManagedIdentityCredentialMissing"; #endregion - public static ConnectionStringValidationResult EvaluateResponseStatus(Exception e, ConnectionStringType type, ConnectionStringValidationResult.ManagedIdentityType identityType) + public static void EvaluateResponseStatus(Exception e, ConnectionStringType type, ref ConnectionStringValidationResult response) { - var response = new ConnectionStringValidationResult(type); if (e is MalformedConnectionStringException) { response.Status = ConnectionStringValidationResult.ResultStatus.MalformedConnectionString; } - else if (e.Message.Contains("managedIdentityCredentialMissing")) + else if (e is EmptyConnectionStringException) { - response.Status = ConnectionStringValidationResult.ResultStatus.ManagedIdentityCredentialMissing; + response.Status = ConnectionStringValidationResult.ResultStatus.EmptyConnectionString; } - else if (e.Message.Contains("Unauthorized") || e.Message.Contains("AuthorizationPermissionMismatch")) + else if (e.Message.Contains(ManagedIdentityCredentialMissing)) { - if (identityType == ConnectionStringValidationResult.ManagedIdentityType.User) - { - response.Status = ConnectionStringValidationResult.ResultStatus.UserAssignedManagedIdentity; - } - else - { - response.Status = ConnectionStringValidationResult.ResultStatus.SystemAssignedManagedIdentity; - } + response.Status = ConnectionStringValidationResult.ResultStatus.ManagedIdentityCredentialMissing; } - else if (e.Message.Contains("ManagedIdentityCredential")) + else if (e.Message.Contains("Unauthorized") || e.Message.Contains("unauthorized") || e.Message.Contains("request is not authorized")) { - response.Status = ConnectionStringValidationResult.ResultStatus.ManagedIdentityCredential; + response.Status = ConnectionStringValidationResult.ResultStatus.ManagedIdentityAuthFailure; } - else if (e.Message.Contains("fullyQualifiedNamespace")) + else if (e is AuthenticationFailedException && e.Message.Contains("ManagedIdentityCredential")) { - response.Status = ConnectionStringValidationResult.ResultStatus.FullyQualifiedNamespaceMissed; + response.Status = ConnectionStringValidationResult.ResultStatus.ManagedIdentityNotConfigured; } - else if (e.Message.Contains("ServiceUriMissed")) + else if (e.Message.Contains("fullyQualifiedNamespace")) { - response.Status = ConnectionStringValidationResult.ResultStatus.ServiceUriMissed; + response.Status = ConnectionStringValidationResult.ResultStatus.FullyQualifiedNamespaceMissing; } - else if (e is EmptyConnectionStringException) + else if (e.Message.Contains("ServiceUriMissing")) { - response.Status = ConnectionStringValidationResult.ResultStatus.EmptyConnectionString; + response.Status = ConnectionStringValidationResult.ResultStatus.ServiceUriMissing; } else if (e.InnerException != null && e.InnerException.Message.Contains("The remote name could not be resolved")) @@ -89,15 +88,13 @@ public static ConnectionStringValidationResult EvaluateResponseStatus(Exception { response.Status = ConnectionStringValidationResult.ResultStatus.MalformedConnectionString; } - else if (e.Message.Contains("InvalidSignature") || - e.Message.Contains("Unauthorized")) + else if (e.Message.Contains("InvalidSignature")) { response.Status = ConnectionStringValidationResult.ResultStatus.AuthFailure; } - else if ((e is ArgumentException && e.Message.Contains("Authentication ")) || + else if ((e is ArgumentException && e.Message.Contains("Authentication")) || e.Message.Contains("claim is empty or token is invalid") || - e.Message.Contains("InvalidSignature") || - e.Message.Contains("Unauthorized")) + e.Message.Contains("InvalidSignature")) { response.Status = ConnectionStringValidationResult.ResultStatus.AuthFailure; } @@ -121,8 +118,6 @@ public static ConnectionStringValidationResult EvaluateResponseStatus(Exception response.Status = ConnectionStringValidationResult.ResultStatus.UnknownError; } response.Exception = e; - - return response; } } } diff --git a/DiagnosticsExtension/Models/ConnectionStringValidator/FileShareStorageValidator.cs b/DiagnosticsExtension/Models/ConnectionStringValidator/FileShareStorageValidator.cs index 7bda9883..1151d8c2 100644 --- a/DiagnosticsExtension/Models/ConnectionStringValidator/FileShareStorageValidator.cs +++ b/DiagnosticsExtension/Models/ConnectionStringValidator/FileShareStorageValidator.cs @@ -22,17 +22,14 @@ namespace DiagnosticsExtension.Models.ConnectionStringValidator public class FileShareStorageValidator : IConnectionStringValidator { public string ProviderName => "Microsoft.WindowsAzure.Storage"; - public ConnectionStringType Type => ConnectionStringType.FileShareStorageAccount; - - ConnectionStringValidationResult.ManagedIdentityType identityType; public async Task ValidateViaAppsettingAsync(string appsettingname, string entityName) { var response = new ConnectionStringValidationResult(Type); try { - var result = await TestConnectionStringViaAppSetting(appsettingname, entityName); + var result = await TestConnectionStringViaAppSettingAsync(appsettingname, entityName); if (result.Succeeded) { response.Status = ConnectionStringValidationResult.ResultStatus.Success; @@ -44,13 +41,13 @@ public async Task ValidateViaAppsettingAsync(s } catch (Exception e) { - response = ConnectionStringResponseUtility.EvaluateResponseStatus(e, Type, identityType); + ConnectionStringResponseUtility.EvaluateResponseStatus(e, Type, ref response); } return response; } - public async Task TestConnectionStringViaAppSetting(string appSettingName, string entityName) + public async Task TestConnectionStringViaAppSettingAsync(string appSettingName, string entityName) { string value = ""; var envDict = Environment.GetEnvironmentVariables(); diff --git a/DiagnosticsExtension/Models/ConnectionStringValidator/QueueStorageValidator.cs b/DiagnosticsExtension/Models/ConnectionStringValidator/QueueStorageValidator.cs index 9ee734c2..54ef2cdb 100644 --- a/DiagnosticsExtension/Models/ConnectionStringValidator/QueueStorageValidator.cs +++ b/DiagnosticsExtension/Models/ConnectionStringValidator/QueueStorageValidator.cs @@ -22,17 +22,15 @@ namespace DiagnosticsExtension.Models.ConnectionStringValidator public class QueueStorageValidator : IConnectionStringValidator { public string ProviderName => "Microsoft.WindowsAzure.Storage"; - public ConnectionStringType Type => ConnectionStringType.QueueStorageAccount; - - ConnectionStringValidationResult.ManagedIdentityType identityType; + public ConnectionStringValidationResult response = null; public async Task ValidateViaAppsettingAsync(string appsettingname, string entityName) { - var response = new ConnectionStringValidationResult(Type); + response = new ConnectionStringValidationResult(Type); try { - var result = await TestConnectionStringViaAppSetting(appsettingname, entityName); + var result = await TestConnectionStringViaAppSettingAsync(appsettingname, entityName); if (result.Succeeded) { response.Status = ConnectionStringValidationResult.ResultStatus.Success; @@ -44,13 +42,13 @@ public async Task ValidateViaAppsettingAsync(s } catch (Exception e) { - response = ConnectionStringResponseUtility.EvaluateResponseStatus(e, Type, identityType); + ConnectionStringResponseUtility.EvaluateResponseStatus(e, Type, ref response); } return response; } - public async Task TestConnectionStringViaAppSetting(string appSettingName, string entityName) + public async Task TestConnectionStringViaAppSettingAsync(string appSettingName, string entityName) { var envDict = Environment.GetEnvironmentVariables(); string appSettingClientIdValue, appSettingClientCredValue = null; @@ -74,42 +72,35 @@ public async Task TestConnectionStringViaAppSetting(string a } else { - try + string serviceUriString = Environment.GetEnvironmentVariable(appSettingName + ConnectionStringResponseUtility.QueueServiceUri); + if (!string.IsNullOrEmpty(serviceUriString)) { - string serviceUriString = Environment.GetEnvironmentVariable(appSettingName + "__queueServiceUri"); - if (!string.IsNullOrEmpty(serviceUriString)) + appSettingClientIdValue = Environment.GetEnvironmentVariable(appSettingName + ConnectionStringResponseUtility.ClientId); + appSettingClientCredValue = Environment.GetEnvironmentVariable(appSettingName + ConnectionStringResponseUtility.Credential); + Uri serviceUri = new Uri(serviceUriString); + // Creating client using User assigned managed identity + if (!string.IsNullOrEmpty(appSettingClientIdValue)) { - appSettingClientIdValue = Environment.GetEnvironmentVariable(appSettingName + ConnectionStringResponseUtility.ClientId); - appSettingClientCredValue = Environment.GetEnvironmentVariable(appSettingName + ConnectionStringResponseUtility.Credential); - Uri serviceUri = new Uri(serviceUriString); - // Creating client using User assigned managed identity - if (!string.IsNullOrEmpty(appSettingClientIdValue)) + if (appSettingClientCredValue != ConnectionStringResponseUtility.ValidCredentialValue) { - if (appSettingClientCredValue != ConnectionStringResponseUtility.ValidCredentialValue) - { - throw new ManagedIdentityException(ConnectionStringResponseUtility.ManagedIdentityCredentialMissing); - } - else - { - identityType = ConnectionStringValidationResult.ManagedIdentityType.User; - client = new QueueServiceClient(serviceUri, new Azure.Identity.ManagedIdentityCredential(appSettingClientIdValue)); - } + throw new ManagedIdentityException(ConnectionStringResponseUtility.ManagedIdentityCredentialMissing); } - // Creating client using System assigned managed identity else { - identityType = ConnectionStringValidationResult.ManagedIdentityType.System; - client = new QueueServiceClient(serviceUri, new Azure.Identity.ManagedIdentityCredential()); + response.IdentityType = ConnectionStringResponseUtility.User; + client = new QueueServiceClient(serviceUri, new Azure.Identity.ManagedIdentityCredential(appSettingClientIdValue)); } } + // Creating client using System assigned managed identity else { - throw new ManagedIdentityException(ConnectionStringResponseUtility.ServiceUriMissed); + response.IdentityType = ConnectionStringResponseUtility.System; + client = new QueueServiceClient(serviceUri, new Azure.Identity.ManagedIdentityCredential()); } } - catch (Exception e) + else { - throw new ManagedIdentityException(e.Message, e); + throw new ManagedIdentityException(ConnectionStringResponseUtility.ServiceUriMissing); } } client.GetQueuesAsync(); diff --git a/DiagnosticsExtension/Models/ConnectionStringValidator/ServiceBusValidator.cs b/DiagnosticsExtension/Models/ConnectionStringValidator/ServiceBusValidator.cs index 89aba27e..0f4ad7f9 100644 --- a/DiagnosticsExtension/Models/ConnectionStringValidator/ServiceBusValidator.cs +++ b/DiagnosticsExtension/Models/ConnectionStringValidator/ServiceBusValidator.cs @@ -20,10 +20,9 @@ namespace DiagnosticsExtension.Models.ConnectionStringValidator public class ServiceBusValidator : IConnectionStringValidator { public string ProviderName => "Microsoft.Azure.ServiceBus"; - + public ConnectionStringValidationResult response = null; public ConnectionStringType Type => ConnectionStringType.ServiceBus; - ConnectionStringValidationResult.ManagedIdentityType identityType; public Task IsValidAsync(string connectionString) { try @@ -39,7 +38,7 @@ public Task IsValidAsync(string connectionString) async public Task ValidateAsync(string connectionString, string clientId = null) { - var response = new ConnectionStringValidationResult(Type); + response = new ConnectionStringValidationResult(Type); try { @@ -55,7 +54,7 @@ async public Task ValidateAsync(string connect } catch (Exception e) { - response = ConnectionStringResponseUtility.EvaluateResponseStatus(e, Type, identityType); + ConnectionStringResponseUtility.EvaluateResponseStatus(e, Type, ref response); } return response; @@ -90,7 +89,7 @@ protected async Task TestConnectionStringAsync(string connec } async public Task ValidateViaAppsettingAsync(string appsettingName, string entityName) { - var response = new ConnectionStringValidationResult(Type); + response = new ConnectionStringValidationResult(Type); try { @@ -106,7 +105,7 @@ async public Task ValidateViaAppsettingAsync(s } catch (Exception e) { - response = ConnectionStringResponseUtility.EvaluateResponseStatus(e, Type, identityType); + ConnectionStringResponseUtility.EvaluateResponseStatus(e, Type, ref response); } return response; @@ -128,39 +127,30 @@ protected async Task TestConnectionStringViaAppSettingAsync( { throw new MalformedConnectionStringException(e.Message, e); } - } else { - try + string serviceUriString = Environment.GetEnvironmentVariable(appSettingName + ConnectionStringResponseUtility.FullyQualifiedNamespace); + appSettingClientIdValue = Environment.GetEnvironmentVariable(appSettingName + ConnectionStringResponseUtility.ClientId); + appSettingClientCredValue = Environment.GetEnvironmentVariable(appSettingName + ConnectionStringResponseUtility.Credential); + // Creating client using User assigned managed identity + if (!string.IsNullOrEmpty(appSettingClientIdValue)) { - string serviceUriString = Environment.GetEnvironmentVariable(appSettingName + ConnectionStringResponseUtility.FullyQualifiedNamespace); - appSettingClientIdValue = Environment.GetEnvironmentVariable(appSettingName + ConnectionStringResponseUtility.ClientId); - appSettingClientCredValue = Environment.GetEnvironmentVariable(appSettingName + ConnectionStringResponseUtility.Credential); - // Creating client using User assigned managed identity - if (!string.IsNullOrEmpty(appSettingClientIdValue)) + if (appSettingClientCredValue != ConnectionStringResponseUtility.ValidCredentialValue) { - if (appSettingClientCredValue != ConnectionStringResponseUtility.ValidCredentialValue) - { - - throw new ManagedIdentityException(ConnectionStringResponseUtility.ManagedIdentityCredentialMissing); - } - else - { - identityType = ConnectionStringValidationResult.ManagedIdentityType.User; - client = new ServiceBusClient(serviceUriString, new Azure.Identity.ManagedIdentityCredential(appSettingClientIdValue)); - } + throw new ManagedIdentityException(ConnectionStringResponseUtility.ManagedIdentityCredentialMissing); } - // Creating client using System assigned managed identity else { - identityType = ConnectionStringValidationResult.ManagedIdentityType.System; - client = new ServiceBusClient(serviceUriString, new Azure.Identity.ManagedIdentityCredential()); + response.IdentityType = ConnectionStringResponseUtility.User; + client = new ServiceBusClient(serviceUriString, new Azure.Identity.ManagedIdentityCredential(appSettingClientIdValue)); } } - catch (Exception e) + // Creating client using System assigned managed identity + else { - throw new ManagedIdentityException(e.Message, e); + response.IdentityType = ConnectionStringResponseUtility.System; + client = new ServiceBusClient(serviceUriString, new Azure.Identity.ManagedIdentityCredential()); } } TestConnectionData data = new TestConnectionData From 05610223dddfc93c1be6c301078b52df68f1d75b Mon Sep 17 00:00:00 2001 From: Gajibilli Koteswara Rao Date: Wed, 9 Mar 2022 20:00:02 +0530 Subject: [PATCH 07/26] Code modified as per the comments --- .../BlobStorageValidator.cs | 134 ++++++++---------- .../EventHubsValidator.cs | 112 ++++++--------- .../ConnectionStringResponseUtility.cs | 15 +- .../QueueStorageValidator.cs | 128 +++++++---------- .../ServiceBusValidator.cs | 109 ++++++-------- 5 files changed, 215 insertions(+), 283 deletions(-) diff --git a/DiagnosticsExtension/Models/ConnectionStringValidator/BlobStorageValidator.cs b/DiagnosticsExtension/Models/ConnectionStringValidator/BlobStorageValidator.cs index c33375ae..ee3d0e7f 100644 --- a/DiagnosticsExtension/Models/ConnectionStringValidator/BlobStorageValidator.cs +++ b/DiagnosticsExtension/Models/ConnectionStringValidator/BlobStorageValidator.cs @@ -22,105 +22,85 @@ public class BlobStorageValidator : IConnectionStringValidator { public string ProviderName => "Microsoft.WindowsAzure.Storage"; public ConnectionStringType Type => ConnectionStringType.BlobStorageAccount; - public ConnectionStringValidationResult response = null; - public async Task ValidateViaAppsettingAsync(string appsettingname, string entityName) + public async Task ValidateViaAppsettingAsync(string appSettingName, string entityName) { - response = new ConnectionStringValidationResult(Type); + ConnectionStringValidationResult response = new ConnectionStringValidationResult(Type); try { - var result = await TestConnectionStringViaAppSettingAsync(appsettingname, entityName); - if (result.Succeeded) - { - response.Status = ConnectionStringValidationResult.ResultStatus.Success; - } - else - { - throw new Exception("Unexpected state reached: result.Succeeded == false is unexpected!"); - } - } - catch (Exception e) - { - ConnectionStringResponseUtility.EvaluateResponseStatus(e, Type, ref response); - } - - return response; - } - - public async Task TestConnectionStringViaAppSettingAsync(string appSettingName, string entityName) - { - var envDict = Environment.GetEnvironmentVariables(); - string appSettingClientIdValue, appSettingClientCredValue = null; - BlobServiceClient client = null; + var envDict = Environment.GetEnvironmentVariables(); + string appSettingClientIdValue, appSettingClientCredValue = null; + BlobServiceClient client = null; - if (envDict.Contains(appSettingName)) - { - try - { - string connectionString = Environment.GetEnvironmentVariable(appSettingName); - client = new BlobServiceClient(connectionString); - } - catch (ArgumentNullException e) - { - throw new EmptyConnectionStringException(e.Message, e); - } - catch (Exception e) - { - throw new MalformedConnectionStringException(e.Message, e); - } - } - else - { - string serviceUriString = Environment.GetEnvironmentVariable(appSettingName + ConnectionStringResponseUtility.BlobServiceUri); - if (string.IsNullOrEmpty(serviceUriString)) + if (envDict.Contains(appSettingName)) { - serviceUriString = Environment.GetEnvironmentVariable(appSettingName + ConnectionStringResponseUtility.ServiceUri); + try + { + string connectionString = Environment.GetEnvironmentVariable(appSettingName); + client = new BlobServiceClient(connectionString); + } + catch (ArgumentNullException e) + { + throw new EmptyConnectionStringException(e.Message, e); + } + catch (Exception e) + { + throw new MalformedConnectionStringException(e.Message, e); + } } - if (!string.IsNullOrEmpty(serviceUriString)) + else { - appSettingClientIdValue = Environment.GetEnvironmentVariable(appSettingName + ConnectionStringResponseUtility.ClientId); - appSettingClientCredValue = Environment.GetEnvironmentVariable(appSettingName + ConnectionStringResponseUtility.Credential); - Uri serviceUri = new Uri(serviceUriString); - // Creating client using User assigned managed identity - if (!string.IsNullOrEmpty(appSettingClientIdValue)) + string serviceUriString = Environment.GetEnvironmentVariable(appSettingName + ConnectionStringResponseUtility.BlobServiceUri); + if (string.IsNullOrEmpty(serviceUriString)) + { + serviceUriString = Environment.GetEnvironmentVariable(appSettingName + ConnectionStringResponseUtility.ServiceUri); + } + if (!string.IsNullOrEmpty(serviceUriString)) { - if (appSettingClientCredValue != ConnectionStringResponseUtility.ValidCredentialValue) + appSettingClientIdValue = Environment.GetEnvironmentVariable(appSettingName + ConnectionStringResponseUtility.ClientId); + appSettingClientCredValue = Environment.GetEnvironmentVariable(appSettingName + ConnectionStringResponseUtility.Credential); + Uri serviceUri = new Uri(serviceUriString); + // Creating client using User assigned managed identity + if (!string.IsNullOrEmpty(appSettingClientIdValue)) { - throw new ManagedIdentityException(ConnectionStringResponseUtility.ManagedIdentityCredentialMissing); + if (appSettingClientCredValue != ConnectionStringResponseUtility.ValidCredentialValue) + { + throw new ManagedIdentityException(ConnectionStringResponseUtility.ManagedIdentityCredentialMissing); + } + else + { + response.IdentityType = ConnectionStringResponseUtility.User; + client = new BlobServiceClient(serviceUri, new Azure.Identity.ManagedIdentityCredential(appSettingClientIdValue)); + } } + // Creating client using System assigned managed identity else { - response.IdentityType = ConnectionStringResponseUtility.User; - client = new BlobServiceClient(serviceUri, new Azure.Identity.ManagedIdentityCredential(appSettingClientIdValue)); + response.IdentityType = ConnectionStringResponseUtility.System; + client = new BlobServiceClient(serviceUri, new Azure.Identity.ManagedIdentityCredential()); } } - // Creating client using System assigned managed identity else { - response.IdentityType = ConnectionStringResponseUtility.System; - client = new BlobServiceClient(serviceUri, new Azure.Identity.ManagedIdentityCredential()); + throw new ManagedIdentityException(ConnectionStringResponseUtility.ServiceUriMissing); } } - else - { - throw new ManagedIdentityException(ConnectionStringResponseUtility.ServiceUriMissing); - } - } - client.GetBlobContainersAsync(); - var resultSegment = - client.GetBlobContainers(BlobContainerTraits.Metadata, null, default) - .AsPages(default, 10); - //need to read at least one result item to confirm authorization check for connection - resultSegment.Single(); + client.GetBlobContainersAsync(); + var resultSegment = + client.GetBlobContainers(BlobContainerTraits.Metadata, null, default) + .AsPages(default, 10); + //need to read at least one result item to confirm authorization check for connection + resultSegment.Single(); - TestConnectionData data = new TestConnectionData + response.Status = ConnectionStringValidationResult.ResultStatus.Success; + } + catch (Exception e) { - ConnectionString = client.ToString(), - Succeeded = true - }; - return data; - } + ConnectionStringResponseUtility.EvaluateResponseStatus(e, Type, ref response); + } + return response; + } public async Task ValidateAsync(string connStr, string clientId = null) { throw new NotImplementedException(); diff --git a/DiagnosticsExtension/Models/ConnectionStringValidator/EventHubsValidator.cs b/DiagnosticsExtension/Models/ConnectionStringValidator/EventHubsValidator.cs index 8111aac1..a6233232 100644 --- a/DiagnosticsExtension/Models/ConnectionStringValidator/EventHubsValidator.cs +++ b/DiagnosticsExtension/Models/ConnectionStringValidator/EventHubsValidator.cs @@ -19,7 +19,6 @@ public class EventHubsValidator : IConnectionStringValidator { public string ProviderName => "Microsoft.Azure.EventHubs"; public ConnectionStringType Type => ConnectionStringType.EventHubs; - public ConnectionStringValidationResult response = null; public Task IsValidAsync(string connectionString) { try @@ -35,7 +34,7 @@ public Task IsValidAsync(string connectionString) async public Task ValidateAsync(string connectionString, string clientId = null) { - response = new ConnectionStringValidationResult(Type); + ConnectionStringValidationResult response = new ConnectionStringValidationResult(Type); try { @@ -72,90 +71,73 @@ protected async Task TestConnectionStringAsync(string connec return data; } - async public Task ValidateViaAppsettingAsync(string appsettingName, string entityName) + async public Task ValidateViaAppsettingAsync(string appSettingName, string entityName) { - response = new ConnectionStringValidationResult(Type); + ConnectionStringValidationResult response = new ConnectionStringValidationResult(Type); try { - var result = await TestConnectionStringViaAppSettingAsync(appsettingName, entityName); - if (result.Succeeded) - { - response.Status = ConnectionStringValidationResult.ResultStatus.Success; - } - else - { - throw new Exception("Unexpected state reached: result.Succeeded == false is unexpected!"); - } - } - catch (Exception e) - { - ConnectionStringResponseUtility.EvaluateResponseStatus(e, Type, ref response); - } - - return response; - } - protected async Task TestConnectionStringViaAppSettingAsync(string appSettingName, string entityName) - { - string appSettingClientIdValue, appSettingClientCredValue = ""; - EventHubProducerClient client = null; - var envDict = Environment.GetEnvironmentVariables(); - string eventHubName = entityName; + string appSettingClientIdValue, appSettingClientCredValue = ""; + EventHubProducerClient client = null; + var envDict = Environment.GetEnvironmentVariables(); + string eventHubName = entityName; - if (envDict.Contains(appSettingName)) - { - try - { - string connectionString = Environment.GetEnvironmentVariable(appSettingName); - client = new EventHubProducerClient(connectionString); - } - catch (Exception e) + if (envDict.Contains(appSettingName)) { - throw new MalformedConnectionStringException(e.Message, e); + try + { + string connectionString = Environment.GetEnvironmentVariable(appSettingName); + connectionString += ";EntityPath="+eventHubName; + client = new EventHubProducerClient(connectionString); + } + catch (Exception e) + { + throw new MalformedConnectionStringException(e.Message, e); + } } - } - else - { - try + else { - string serviceUriString = Environment.GetEnvironmentVariable(appSettingName + ConnectionStringResponseUtility.FullyQualifiedNamespace); - appSettingClientIdValue = Environment.GetEnvironmentVariable(appSettingName + ConnectionStringResponseUtility.ClientId); - appSettingClientCredValue = Environment.GetEnvironmentVariable(appSettingName + ConnectionStringResponseUtility.Credential); - // Creating client using User assigned managed identity - if (!string.IsNullOrEmpty(appSettingClientIdValue)) + try { - if (appSettingClientCredValue != ConnectionStringResponseUtility.ValidCredentialValue) + string serviceUriString = Environment.GetEnvironmentVariable(appSettingName + ConnectionStringResponseUtility.FullyQualifiedNamespace); + appSettingClientIdValue = Environment.GetEnvironmentVariable(appSettingName + ConnectionStringResponseUtility.ClientId); + appSettingClientCredValue = Environment.GetEnvironmentVariable(appSettingName + ConnectionStringResponseUtility.Credential); + // Creating client using User assigned managed identity + if (!string.IsNullOrEmpty(appSettingClientIdValue)) { - throw new ManagedIdentityException(ConnectionStringResponseUtility.ManagedIdentityCredentialMissing); + if (appSettingClientCredValue != ConnectionStringResponseUtility.ValidCredentialValue) + { + throw new ManagedIdentityException(ConnectionStringResponseUtility.ManagedIdentityCredentialMissing); + } + else + { + response.IdentityType = ConnectionStringResponseUtility.User; + client = new EventHubProducerClient(serviceUriString, eventHubName, new ManagedIdentityCredential(appSettingClientIdValue)); + } } + // Creating client using System assigned managed identity else { - response.IdentityType = ConnectionStringResponseUtility.User; - client = new EventHubProducerClient(serviceUriString, eventHubName, new ManagedIdentityCredential(appSettingClientIdValue)); + response.IdentityType = ConnectionStringResponseUtility.System; + client = new EventHubProducerClient(serviceUriString, eventHubName, new ManagedIdentityCredential()); } } - // Creating client using System assigned managed identity - else + catch (Exception e) { - response.IdentityType = ConnectionStringResponseUtility.System; - client = new EventHubProducerClient(serviceUriString, eventHubName, new ManagedIdentityCredential()); + throw new ManagedIdentityException(e.Message, e); } } - catch (Exception e) - { - throw new ManagedIdentityException(e.Message, e); - } - } - await client.GetPartitionIdsAsync(); - await client.CloseAsync(); + await client.GetPartitionIdsAsync(); + await client.CloseAsync(); - TestConnectionData data = new TestConnectionData + response.Status = ConnectionStringValidationResult.ResultStatus.Success; + } + catch (Exception e) { - ConnectionString = client.ToString(), - Succeeded = true - }; + ConnectionStringResponseUtility.EvaluateResponseStatus(e, Type, ref response); + } - return data; + return response; } } } diff --git a/DiagnosticsExtension/Models/ConnectionStringValidator/Exceptions/ConnectionStringResponseUtility.cs b/DiagnosticsExtension/Models/ConnectionStringValidator/Exceptions/ConnectionStringResponseUtility.cs index d53041ed..566a6db1 100644 --- a/DiagnosticsExtension/Models/ConnectionStringValidator/Exceptions/ConnectionStringResponseUtility.cs +++ b/DiagnosticsExtension/Models/ConnectionStringValidator/Exceptions/ConnectionStringResponseUtility.cs @@ -41,13 +41,20 @@ public static void EvaluateResponseStatus(Exception e, ConnectionStringType type { response.Status = ConnectionStringValidationResult.ResultStatus.EmptyConnectionString; } - else if (e.Message.Contains(ManagedIdentityCredentialMissing)) + else if (e is ManagedIdentityException && e.Message.Contains(ManagedIdentityCredentialMissing)) { response.Status = ConnectionStringValidationResult.ResultStatus.ManagedIdentityCredentialMissing; } - else if (e.Message.Contains("Unauthorized") || e.Message.Contains("unauthorized") || e.Message.Contains("request is not authorized")) + else if (e is UnauthorizedAccessException && e.Message.Contains("unauthorized") || e.Message.Contains("Unauthorized") || e.Message.Contains("request is not authorized")) { - response.Status = ConnectionStringValidationResult.ResultStatus.ManagedIdentityAuthFailure; + if (string.IsNullOrEmpty(response.IdentityType)) + { + response.Status = ConnectionStringValidationResult.ResultStatus.AuthFailure; + } + else + { + response.Status = ConnectionStringValidationResult.ResultStatus.ManagedIdentityAuthFailure; + } } else if (e is AuthenticationFailedException && e.Message.Contains("ManagedIdentityCredential")) { @@ -57,7 +64,7 @@ public static void EvaluateResponseStatus(Exception e, ConnectionStringType type { response.Status = ConnectionStringValidationResult.ResultStatus.FullyQualifiedNamespaceMissing; } - else if (e.Message.Contains("ServiceUriMissing")) + else if (e is ManagedIdentityException && e.Message.Contains("ServiceUriMissing")) { response.Status = ConnectionStringValidationResult.ResultStatus.ServiceUriMissing; } diff --git a/DiagnosticsExtension/Models/ConnectionStringValidator/QueueStorageValidator.cs b/DiagnosticsExtension/Models/ConnectionStringValidator/QueueStorageValidator.cs index 54ef2cdb..52d8bf70 100644 --- a/DiagnosticsExtension/Models/ConnectionStringValidator/QueueStorageValidator.cs +++ b/DiagnosticsExtension/Models/ConnectionStringValidator/QueueStorageValidator.cs @@ -23,104 +23,84 @@ public class QueueStorageValidator : IConnectionStringValidator { public string ProviderName => "Microsoft.WindowsAzure.Storage"; public ConnectionStringType Type => ConnectionStringType.QueueStorageAccount; - public ConnectionStringValidationResult response = null; - public async Task ValidateViaAppsettingAsync(string appsettingname, string entityName) + public async Task ValidateViaAppsettingAsync(string appSettingName, string entityName) { - response = new ConnectionStringValidationResult(Type); + ConnectionStringValidationResult response = new ConnectionStringValidationResult(Type); try { - var result = await TestConnectionStringViaAppSettingAsync(appsettingname, entityName); - if (result.Succeeded) - { - response.Status = ConnectionStringValidationResult.ResultStatus.Success; - } - else - { - throw new Exception("Unexpected state reached: result.Succeeded == false is unexpected!"); - } - } - catch (Exception e) - { - ConnectionStringResponseUtility.EvaluateResponseStatus(e, Type, ref response); - } + var envDict = Environment.GetEnvironmentVariables(); + string appSettingClientIdValue, appSettingClientCredValue = null; + QueueServiceClient client = null; - return response; - } - - public async Task TestConnectionStringViaAppSettingAsync(string appSettingName, string entityName) - { - var envDict = Environment.GetEnvironmentVariables(); - string appSettingClientIdValue, appSettingClientCredValue = null; - QueueServiceClient client = null; - - if (envDict.Contains(appSettingName)) - { - try - { - string connectionString = Environment.GetEnvironmentVariable(appSettingName); - client = new QueueServiceClient(connectionString); - } - catch (ArgumentNullException e) - { - throw new EmptyConnectionStringException(e.Message, e); - } - catch (Exception e) + if (envDict.Contains(appSettingName)) { - throw new MalformedConnectionStringException(e.Message, e); + try + { + string connectionString = Environment.GetEnvironmentVariable(appSettingName); + client = new QueueServiceClient(connectionString); + } + catch (ArgumentNullException e) + { + throw new EmptyConnectionStringException(e.Message, e); + } + catch (Exception e) + { + throw new MalformedConnectionStringException(e.Message, e); + } } - } - else - { - string serviceUriString = Environment.GetEnvironmentVariable(appSettingName + ConnectionStringResponseUtility.QueueServiceUri); - if (!string.IsNullOrEmpty(serviceUriString)) + else { - appSettingClientIdValue = Environment.GetEnvironmentVariable(appSettingName + ConnectionStringResponseUtility.ClientId); - appSettingClientCredValue = Environment.GetEnvironmentVariable(appSettingName + ConnectionStringResponseUtility.Credential); - Uri serviceUri = new Uri(serviceUriString); - // Creating client using User assigned managed identity - if (!string.IsNullOrEmpty(appSettingClientIdValue)) + string serviceUriString = Environment.GetEnvironmentVariable(appSettingName + ConnectionStringResponseUtility.QueueServiceUri); + if (!string.IsNullOrEmpty(serviceUriString)) { - if (appSettingClientCredValue != ConnectionStringResponseUtility.ValidCredentialValue) + appSettingClientIdValue = Environment.GetEnvironmentVariable(appSettingName + ConnectionStringResponseUtility.ClientId); + appSettingClientCredValue = Environment.GetEnvironmentVariable(appSettingName + ConnectionStringResponseUtility.Credential); + Uri serviceUri = new Uri(serviceUriString); + // Creating client using User assigned managed identity + if (!string.IsNullOrEmpty(appSettingClientIdValue)) { - throw new ManagedIdentityException(ConnectionStringResponseUtility.ManagedIdentityCredentialMissing); + if (appSettingClientCredValue != ConnectionStringResponseUtility.ValidCredentialValue) + { + throw new ManagedIdentityException(ConnectionStringResponseUtility.ManagedIdentityCredentialMissing); + } + else + { + response.IdentityType = ConnectionStringResponseUtility.User; + client = new QueueServiceClient(serviceUri, new Azure.Identity.ManagedIdentityCredential(appSettingClientIdValue)); + } } + // Creating client using System assigned managed identity else { - response.IdentityType = ConnectionStringResponseUtility.User; - client = new QueueServiceClient(serviceUri, new Azure.Identity.ManagedIdentityCredential(appSettingClientIdValue)); + response.IdentityType = ConnectionStringResponseUtility.System; + client = new QueueServiceClient(serviceUri, new Azure.Identity.ManagedIdentityCredential()); } } - // Creating client using System assigned managed identity else { - response.IdentityType = ConnectionStringResponseUtility.System; - client = new QueueServiceClient(serviceUri, new Azure.Identity.ManagedIdentityCredential()); + throw new ManagedIdentityException(ConnectionStringResponseUtility.ServiceUriMissing); } } - else + client.GetQueuesAsync(); + var resultSegment = + client.GetQueues(QueueTraits.Metadata, null, default) + .AsPages(default, 10); + foreach (Azure.Page containerPage in resultSegment) { - throw new ManagedIdentityException(ConnectionStringResponseUtility.ServiceUriMissing); + foreach (QueueItem containerItem in containerPage.Values) + { + string containerName = containerItem.Name.ToString(); + } } + response.Status = ConnectionStringValidationResult.ResultStatus.Success; } - client.GetQueuesAsync(); - var resultSegment = - client.GetQueues(QueueTraits.Metadata, null, default) - .AsPages(default, 10); - foreach (Azure.Page containerPage in resultSegment) + catch (Exception e) { - foreach (QueueItem containerItem in containerPage.Values) - { - string containerName = containerItem.Name.ToString(); - } - + ConnectionStringResponseUtility.EvaluateResponseStatus(e, Type, ref response); } - TestConnectionData data = new TestConnectionData - { - ConnectionString = client.ToString(), - Succeeded = true - }; - return data; + + return response; } public async Task ValidateAsync(string connStr, string clientId = null) { diff --git a/DiagnosticsExtension/Models/ConnectionStringValidator/ServiceBusValidator.cs b/DiagnosticsExtension/Models/ConnectionStringValidator/ServiceBusValidator.cs index 0f4ad7f9..57d9af01 100644 --- a/DiagnosticsExtension/Models/ConnectionStringValidator/ServiceBusValidator.cs +++ b/DiagnosticsExtension/Models/ConnectionStringValidator/ServiceBusValidator.cs @@ -20,7 +20,6 @@ namespace DiagnosticsExtension.Models.ConnectionStringValidator public class ServiceBusValidator : IConnectionStringValidator { public string ProviderName => "Microsoft.Azure.ServiceBus"; - public ConnectionStringValidationResult response = null; public ConnectionStringType Type => ConnectionStringType.ServiceBus; public Task IsValidAsync(string connectionString) @@ -38,7 +37,7 @@ public Task IsValidAsync(string connectionString) async public Task ValidateAsync(string connectionString, string clientId = null) { - response = new ConnectionStringValidationResult(Type); + ConnectionStringValidationResult response = new ConnectionStringValidationResult(Type); try { @@ -87,84 +86,68 @@ protected async Task TestConnectionStringAsync(string connec return data; } - async public Task ValidateViaAppsettingAsync(string appsettingName, string entityName) + async public Task ValidateViaAppsettingAsync(string appSettingName, string entityName) { - response = new ConnectionStringValidationResult(Type); + ConnectionStringValidationResult response = new ConnectionStringValidationResult(Type); try { - var result = await TestConnectionStringViaAppSettingAsync(appsettingName, entityName); - if (result.Succeeded) - { - response.Status = ConnectionStringValidationResult.ResultStatus.Success; - } - else - { - throw new Exception("Unexpected state reached: result.Succeeded == false is unexpected!"); - } - } - catch (Exception e) - { - ConnectionStringResponseUtility.EvaluateResponseStatus(e, Type, ref response); - } - - return response; - } - protected async Task TestConnectionStringViaAppSettingAsync(string appSettingName, string entityName) - { - string appSettingClientIdValue, appSettingClientCredValue = ""; - ServiceBusClient client = null; - var envDict = Environment.GetEnvironmentVariables(); + string appSettingClientIdValue, appSettingClientCredValue = ""; + ServiceBusClient client = null; + var envDict = Environment.GetEnvironmentVariables(); - if (envDict.Contains(appSettingName)) - { - try - { - string connectionString = Environment.GetEnvironmentVariable(appSettingName); - client = new ServiceBusClient(connectionString); - } - catch (Exception e) + if (envDict.Contains(appSettingName)) { - throw new MalformedConnectionStringException(e.Message, e); - } - } - else - { - string serviceUriString = Environment.GetEnvironmentVariable(appSettingName + ConnectionStringResponseUtility.FullyQualifiedNamespace); - appSettingClientIdValue = Environment.GetEnvironmentVariable(appSettingName + ConnectionStringResponseUtility.ClientId); - appSettingClientCredValue = Environment.GetEnvironmentVariable(appSettingName + ConnectionStringResponseUtility.Credential); - // Creating client using User assigned managed identity - if (!string.IsNullOrEmpty(appSettingClientIdValue)) - { - if (appSettingClientCredValue != ConnectionStringResponseUtility.ValidCredentialValue) + try { - throw new ManagedIdentityException(ConnectionStringResponseUtility.ManagedIdentityCredentialMissing); + string connectionString = Environment.GetEnvironmentVariable(appSettingName); + connectionString += ";EntityPath=" + entityName; + client = new ServiceBusClient(connectionString); } - else + catch (Exception e) { - response.IdentityType = ConnectionStringResponseUtility.User; - client = new ServiceBusClient(serviceUriString, new Azure.Identity.ManagedIdentityCredential(appSettingClientIdValue)); + throw new MalformedConnectionStringException(e.Message, e); } } - // Creating client using System assigned managed identity else { - response.IdentityType = ConnectionStringResponseUtility.System; - client = new ServiceBusClient(serviceUriString, new Azure.Identity.ManagedIdentityCredential()); + string serviceUriString = Environment.GetEnvironmentVariable(appSettingName + ConnectionStringResponseUtility.FullyQualifiedNamespace); + appSettingClientIdValue = Environment.GetEnvironmentVariable(appSettingName + ConnectionStringResponseUtility.ClientId); + appSettingClientCredValue = Environment.GetEnvironmentVariable(appSettingName + ConnectionStringResponseUtility.Credential); + // Creating client using User assigned managed identity + if (!string.IsNullOrEmpty(appSettingClientIdValue)) + { + if (appSettingClientCredValue != ConnectionStringResponseUtility.ValidCredentialValue) + { + throw new ManagedIdentityException(ConnectionStringResponseUtility.ManagedIdentityCredentialMissing); + } + else + { + response.IdentityType = ConnectionStringResponseUtility.User; + client = new ServiceBusClient(serviceUriString, new Azure.Identity.ManagedIdentityCredential(appSettingClientIdValue)); + } + } + // Creating client using System assigned managed identity + else + { + response.IdentityType = ConnectionStringResponseUtility.System; + client = new ServiceBusClient(serviceUriString, new Azure.Identity.ManagedIdentityCredential()); + } } + ServiceBusReceiverOptions opt = new ServiceBusReceiverOptions(); + opt.ReceiveMode = ServiceBusReceiveMode.PeekLock; + opt.PrefetchCount = 1; + ServiceBusReceiver receiver = client.CreateReceiver(entityName, opt); + ServiceBusReceivedMessage receivedMessage = await receiver.PeekMessageAsync(); + + response.Status = ConnectionStringValidationResult.ResultStatus.Success; } - TestConnectionData data = new TestConnectionData + catch (Exception e) { - ConnectionString = client.ToString(), - Succeeded = true - }; - ServiceBusReceiverOptions opt = new ServiceBusReceiverOptions(); - opt.ReceiveMode = ServiceBusReceiveMode.PeekLock; - opt.PrefetchCount = 1; - ServiceBusReceiver receiver = client.CreateReceiver(entityName, opt); - ServiceBusReceivedMessage receivedMessage = await receiver.PeekMessageAsync(); + ConnectionStringResponseUtility.EvaluateResponseStatus(e, Type, ref response); + } - return data; + return response; } } } From 6df0d71cf881a76e86e2f99364aacb5e3c81b2fa Mon Sep 17 00:00:00 2001 From: Gajibilli Koteswara Rao Date: Fri, 11 Mar 2022 21:57:18 +0530 Subject: [PATCH 08/26] Changed the code as per the comments --- .../BlobStorageValidator.cs | 19 ++++++++-------- .../ConnectionStringValidationResult.cs | 12 +++++++++- .../EventHubsValidator.cs | 19 ++++++++-------- .../ConnectionStringResponseUtility.cs | 22 ++++++++++++++++--- .../QueueStorageValidator.cs | 17 +++++++------- .../ServiceBusValidator.cs | 17 +++++++------- 6 files changed, 68 insertions(+), 38 deletions(-) diff --git a/DiagnosticsExtension/Models/ConnectionStringValidator/BlobStorageValidator.cs b/DiagnosticsExtension/Models/ConnectionStringValidator/BlobStorageValidator.cs index ee3d0e7f..ce5feb15 100644 --- a/DiagnosticsExtension/Models/ConnectionStringValidator/BlobStorageValidator.cs +++ b/DiagnosticsExtension/Models/ConnectionStringValidator/BlobStorageValidator.cs @@ -50,28 +50,29 @@ public async Task ValidateViaAppsettingAsync(s } else { - string serviceUriString = Environment.GetEnvironmentVariable(appSettingName + ConnectionStringResponseUtility.BlobServiceUri); + string serviceUriString = ConnectionStringResponseUtility.ResolveManagedIdentityCommonProperty(appSettingName, ConnectionStringValidationResult.ManagedIdentityCommonProperty.blobServiceUri); if (string.IsNullOrEmpty(serviceUriString)) { - serviceUriString = Environment.GetEnvironmentVariable(appSettingName + ConnectionStringResponseUtility.ServiceUri); + serviceUriString = ConnectionStringResponseUtility.ResolveManagedIdentityCommonProperty(appSettingName, ConnectionStringValidationResult.ManagedIdentityCommonProperty.serviceUri); } if (!string.IsNullOrEmpty(serviceUriString)) { - appSettingClientIdValue = Environment.GetEnvironmentVariable(appSettingName + ConnectionStringResponseUtility.ClientId); - appSettingClientCredValue = Environment.GetEnvironmentVariable(appSettingName + ConnectionStringResponseUtility.Credential); + appSettingClientIdValue = ConnectionStringResponseUtility.ResolveManagedIdentityCommonProperty(appSettingName, ConnectionStringValidationResult.ManagedIdentityCommonProperty.clientId); + appSettingClientCredValue = ConnectionStringResponseUtility.ResolveManagedIdentityCommonProperty(appSettingName, ConnectionStringValidationResult.ManagedIdentityCommonProperty.credential); Uri serviceUri = new Uri(serviceUriString); // Creating client using User assigned managed identity - if (!string.IsNullOrEmpty(appSettingClientIdValue)) + if (appSettingClientCredValue != null) { if (appSettingClientCredValue != ConnectionStringResponseUtility.ValidCredentialValue) { - throw new ManagedIdentityException(ConnectionStringResponseUtility.ManagedIdentityCredentialMissing); + throw new ManagedIdentityException(ConnectionStringResponseUtility.ManagedIdentityCredentialInvalid); } - else + if (string.IsNullOrEmpty(appSettingClientIdValue)) { - response.IdentityType = ConnectionStringResponseUtility.User; - client = new BlobServiceClient(serviceUri, new Azure.Identity.ManagedIdentityCredential(appSettingClientIdValue)); + throw new ManagedIdentityException(ConnectionStringResponseUtility.ManagedIdentityClientIdEmpty); } + response.IdentityType = ConnectionStringResponseUtility.User; + client = new BlobServiceClient(serviceUri, new Azure.Identity.ManagedIdentityCredential(appSettingClientIdValue)); } // Creating client using System assigned managed identity else diff --git a/DiagnosticsExtension/Models/ConnectionStringValidator/ConnectionStringValidationResult.cs b/DiagnosticsExtension/Models/ConnectionStringValidator/ConnectionStringValidationResult.cs index dc96c3d8..b9a497dc 100644 --- a/DiagnosticsExtension/Models/ConnectionStringValidator/ConnectionStringValidationResult.cs +++ b/DiagnosticsExtension/Models/ConnectionStringValidator/ConnectionStringValidationResult.cs @@ -41,7 +41,8 @@ public enum ResultStatus MsiFailure, EmptyConnectionString, MalformedConnectionString, - ManagedIdentityCredentialMissing, + ManagedIdentityCredentialInvalid, + ManagedIdentityClientIdEmpty, FullyQualifiedNamespaceMissing, SystemAssignedIdentityFailure, UserAssignedIdentityFailure, @@ -55,6 +56,15 @@ public enum ManagedIdentityType User, System } + public enum ManagedIdentityCommonProperty + { + fullyQualifiedNamespace, + credential, + clientId, + serviceUri, + blobServiceUri, + queueServiceUri + } } diff --git a/DiagnosticsExtension/Models/ConnectionStringValidator/EventHubsValidator.cs b/DiagnosticsExtension/Models/ConnectionStringValidator/EventHubsValidator.cs index a6233232..b053990c 100644 --- a/DiagnosticsExtension/Models/ConnectionStringValidator/EventHubsValidator.cs +++ b/DiagnosticsExtension/Models/ConnectionStringValidator/EventHubsValidator.cs @@ -87,7 +87,7 @@ async public Task ValidateViaAppsettingAsync(s try { string connectionString = Environment.GetEnvironmentVariable(appSettingName); - connectionString += ";EntityPath="+eventHubName; + connectionString += ";EntityPath=" + eventHubName; client = new EventHubProducerClient(connectionString); } catch (Exception e) @@ -99,21 +99,22 @@ async public Task ValidateViaAppsettingAsync(s { try { - string serviceUriString = Environment.GetEnvironmentVariable(appSettingName + ConnectionStringResponseUtility.FullyQualifiedNamespace); - appSettingClientIdValue = Environment.GetEnvironmentVariable(appSettingName + ConnectionStringResponseUtility.ClientId); - appSettingClientCredValue = Environment.GetEnvironmentVariable(appSettingName + ConnectionStringResponseUtility.Credential); + string serviceUriString = ConnectionStringResponseUtility.ResolveManagedIdentityCommonProperty(appSettingName, ConnectionStringValidationResult.ManagedIdentityCommonProperty.fullyQualifiedNamespace); + appSettingClientIdValue = ConnectionStringResponseUtility.ResolveManagedIdentityCommonProperty(appSettingName, ConnectionStringValidationResult.ManagedIdentityCommonProperty.clientId); + appSettingClientCredValue = ConnectionStringResponseUtility.ResolveManagedIdentityCommonProperty(appSettingName, ConnectionStringValidationResult.ManagedIdentityCommonProperty.credential); // Creating client using User assigned managed identity - if (!string.IsNullOrEmpty(appSettingClientIdValue)) + if (appSettingClientCredValue != null) { if (appSettingClientCredValue != ConnectionStringResponseUtility.ValidCredentialValue) { - throw new ManagedIdentityException(ConnectionStringResponseUtility.ManagedIdentityCredentialMissing); + throw new ManagedIdentityException(ConnectionStringResponseUtility.ManagedIdentityCredentialInvalid); } - else + if (string.IsNullOrEmpty(appSettingClientIdValue)) { - response.IdentityType = ConnectionStringResponseUtility.User; - client = new EventHubProducerClient(serviceUriString, eventHubName, new ManagedIdentityCredential(appSettingClientIdValue)); + throw new ManagedIdentityException(ConnectionStringResponseUtility.ManagedIdentityClientIdEmpty); } + response.IdentityType = ConnectionStringResponseUtility.User; + client = new EventHubProducerClient(serviceUriString, eventHubName, new ManagedIdentityCredential(appSettingClientIdValue)); } // Creating client using System assigned managed identity else diff --git a/DiagnosticsExtension/Models/ConnectionStringValidator/Exceptions/ConnectionStringResponseUtility.cs b/DiagnosticsExtension/Models/ConnectionStringValidator/Exceptions/ConnectionStringResponseUtility.cs index 566a6db1..0eced0b5 100644 --- a/DiagnosticsExtension/Models/ConnectionStringValidator/Exceptions/ConnectionStringResponseUtility.cs +++ b/DiagnosticsExtension/Models/ConnectionStringValidator/Exceptions/ConnectionStringResponseUtility.cs @@ -20,6 +20,8 @@ public static class ConnectionStringResponseUtility #region string constants for network validator public const string User = "User"; public const string System = "System"; + public const string UnderscoreSeperator = "__"; + public const string ColonSeparator = ":"; public const string ClientId = "__clientId"; public const string Credential = "__credential"; public const string ServiceUri = "__serviceUri"; @@ -28,7 +30,8 @@ public static class ConnectionStringResponseUtility public const string QueueServiceUri = "__queueServiceUri"; public const string ValidCredentialValue = "managedidentity"; public const string FullyQualifiedNamespace = "__fullyQualifiedNamespace"; - public const string ManagedIdentityCredentialMissing = "ManagedIdentityCredentialMissing"; + public const string ManagedIdentityClientIdEmpty = "ManagedIdentityClientIdEmpty"; + public const string ManagedIdentityCredentialInvalid = "ManagedIdentityCredentialInvalid"; #endregion public static void EvaluateResponseStatus(Exception e, ConnectionStringType type, ref ConnectionStringValidationResult response) @@ -41,9 +44,13 @@ public static void EvaluateResponseStatus(Exception e, ConnectionStringType type { response.Status = ConnectionStringValidationResult.ResultStatus.EmptyConnectionString; } - else if (e is ManagedIdentityException && e.Message.Contains(ManagedIdentityCredentialMissing)) + else if (e is ManagedIdentityException && e.Message.Contains(ManagedIdentityCredentialInvalid)) { - response.Status = ConnectionStringValidationResult.ResultStatus.ManagedIdentityCredentialMissing; + response.Status = ConnectionStringValidationResult.ResultStatus.ManagedIdentityCredentialInvalid; + } + else if (e is ManagedIdentityException && e.Message.Contains(ManagedIdentityClientIdEmpty)) + { + response.Status = ConnectionStringValidationResult.ResultStatus.ManagedIdentityClientIdEmpty; } else if (e is UnauthorizedAccessException && e.Message.Contains("unauthorized") || e.Message.Contains("Unauthorized") || e.Message.Contains("request is not authorized")) { @@ -126,5 +133,14 @@ public static void EvaluateResponseStatus(Exception e, ConnectionStringType type } response.Exception = e; } + public static string ResolveManagedIdentityCommonProperty(string appSettingName, ConnectionStringValidationResult.ManagedIdentityCommonProperty prop) + { + string commonPropertyValue = Environment.GetEnvironmentVariable(appSettingName + UnderscoreSeperator + prop.ToString()); + if (string.IsNullOrEmpty(commonPropertyValue)) + { + commonPropertyValue = Environment.GetEnvironmentVariable(appSettingName + ColonSeparator + prop.ToString()); + } + return commonPropertyValue; + } } } diff --git a/DiagnosticsExtension/Models/ConnectionStringValidator/QueueStorageValidator.cs b/DiagnosticsExtension/Models/ConnectionStringValidator/QueueStorageValidator.cs index 52d8bf70..16159239 100644 --- a/DiagnosticsExtension/Models/ConnectionStringValidator/QueueStorageValidator.cs +++ b/DiagnosticsExtension/Models/ConnectionStringValidator/QueueStorageValidator.cs @@ -51,24 +51,25 @@ public async Task ValidateViaAppsettingAsync(s } else { - string serviceUriString = Environment.GetEnvironmentVariable(appSettingName + ConnectionStringResponseUtility.QueueServiceUri); + string serviceUriString = ConnectionStringResponseUtility.ResolveManagedIdentityCommonProperty(appSettingName, ConnectionStringValidationResult.ManagedIdentityCommonProperty.queueServiceUri); if (!string.IsNullOrEmpty(serviceUriString)) { - appSettingClientIdValue = Environment.GetEnvironmentVariable(appSettingName + ConnectionStringResponseUtility.ClientId); - appSettingClientCredValue = Environment.GetEnvironmentVariable(appSettingName + ConnectionStringResponseUtility.Credential); + appSettingClientIdValue = ConnectionStringResponseUtility.ResolveManagedIdentityCommonProperty(appSettingName, ConnectionStringValidationResult.ManagedIdentityCommonProperty.clientId); + appSettingClientCredValue = ConnectionStringResponseUtility.ResolveManagedIdentityCommonProperty(appSettingName, ConnectionStringValidationResult.ManagedIdentityCommonProperty.credential); Uri serviceUri = new Uri(serviceUriString); // Creating client using User assigned managed identity - if (!string.IsNullOrEmpty(appSettingClientIdValue)) + if (appSettingClientCredValue != null) { if (appSettingClientCredValue != ConnectionStringResponseUtility.ValidCredentialValue) { - throw new ManagedIdentityException(ConnectionStringResponseUtility.ManagedIdentityCredentialMissing); + throw new ManagedIdentityException(ConnectionStringResponseUtility.ManagedIdentityCredentialInvalid); } - else + if (string.IsNullOrEmpty(appSettingClientIdValue)) { - response.IdentityType = ConnectionStringResponseUtility.User; - client = new QueueServiceClient(serviceUri, new Azure.Identity.ManagedIdentityCredential(appSettingClientIdValue)); + throw new ManagedIdentityException(ConnectionStringResponseUtility.ManagedIdentityClientIdEmpty); } + response.IdentityType = ConnectionStringResponseUtility.User; + client = new QueueServiceClient(serviceUri, new Azure.Identity.ManagedIdentityCredential(appSettingClientIdValue)); } // Creating client using System assigned managed identity else diff --git a/DiagnosticsExtension/Models/ConnectionStringValidator/ServiceBusValidator.cs b/DiagnosticsExtension/Models/ConnectionStringValidator/ServiceBusValidator.cs index 57d9af01..b32dc0f9 100644 --- a/DiagnosticsExtension/Models/ConnectionStringValidator/ServiceBusValidator.cs +++ b/DiagnosticsExtension/Models/ConnectionStringValidator/ServiceBusValidator.cs @@ -111,21 +111,22 @@ async public Task ValidateViaAppsettingAsync(s } else { - string serviceUriString = Environment.GetEnvironmentVariable(appSettingName + ConnectionStringResponseUtility.FullyQualifiedNamespace); - appSettingClientIdValue = Environment.GetEnvironmentVariable(appSettingName + ConnectionStringResponseUtility.ClientId); - appSettingClientCredValue = Environment.GetEnvironmentVariable(appSettingName + ConnectionStringResponseUtility.Credential); + string serviceUriString = ConnectionStringResponseUtility.ResolveManagedIdentityCommonProperty(appSettingName, ConnectionStringValidationResult.ManagedIdentityCommonProperty.fullyQualifiedNamespace); + appSettingClientIdValue = ConnectionStringResponseUtility.ResolveManagedIdentityCommonProperty(appSettingName, ConnectionStringValidationResult.ManagedIdentityCommonProperty.clientId); + appSettingClientCredValue = ConnectionStringResponseUtility.ResolveManagedIdentityCommonProperty(appSettingName, ConnectionStringValidationResult.ManagedIdentityCommonProperty.credential); // Creating client using User assigned managed identity - if (!string.IsNullOrEmpty(appSettingClientIdValue)) + if (appSettingClientCredValue != null) { if (appSettingClientCredValue != ConnectionStringResponseUtility.ValidCredentialValue) { - throw new ManagedIdentityException(ConnectionStringResponseUtility.ManagedIdentityCredentialMissing); + throw new ManagedIdentityException(ConnectionStringResponseUtility.ManagedIdentityCredentialInvalid); } - else + if (string.IsNullOrEmpty(appSettingClientIdValue)) { - response.IdentityType = ConnectionStringResponseUtility.User; - client = new ServiceBusClient(serviceUriString, new Azure.Identity.ManagedIdentityCredential(appSettingClientIdValue)); + throw new ManagedIdentityException(ConnectionStringResponseUtility.ManagedIdentityClientIdEmpty); } + response.IdentityType = ConnectionStringResponseUtility.User; + client = new ServiceBusClient(serviceUriString, new Azure.Identity.ManagedIdentityCredential(appSettingClientIdValue)); } // Creating client using System assigned managed identity else From 46ab0ff0080de473ddf1dd01bba87b177986a0f5 Mon Sep 17 00:00:00 2001 From: Gajibilli Koteswara Rao Date: Thu, 24 Mar 2022 23:08:03 +0530 Subject: [PATCH 09/26] Changed the code as per the comments --- .../DiagnosticsExtension.csproj | 3 + .../BlobStorageValidator.cs | 44 +++++--- .../ConnectionStringValidationResult.cs | 10 +- .../ConnectionStringValidator/Constants.cs | 52 +++++++++ .../EventHubsValidator.cs | 49 +++++---- .../ConnectionStringResponseUtility.cs | 93 +++++++--------- ...anagedIdentityConnectionResponseUtility.cs | 103 ++++++++++++++++++ ...ManagedIdentityCredentialTokenValidator.cs | 41 +++++++ .../QueueStorageValidator.cs | 32 ++++-- .../ServiceBusValidator.cs | 28 +++-- 10 files changed, 332 insertions(+), 123 deletions(-) create mode 100644 DiagnosticsExtension/Models/ConnectionStringValidator/Constants.cs create mode 100644 DiagnosticsExtension/Models/ConnectionStringValidator/Exceptions/ManagedIdentityConnectionResponseUtility.cs create mode 100644 DiagnosticsExtension/Models/ConnectionStringValidator/ManagedIdentityCredentialTokenValidator.cs diff --git a/DiagnosticsExtension/DiagnosticsExtension.csproj b/DiagnosticsExtension/DiagnosticsExtension.csproj index 4e16c0f3..b4f9ccf5 100644 --- a/DiagnosticsExtension/DiagnosticsExtension.csproj +++ b/DiagnosticsExtension/DiagnosticsExtension.csproj @@ -384,11 +384,14 @@ + + + diff --git a/DiagnosticsExtension/Models/ConnectionStringValidator/BlobStorageValidator.cs b/DiagnosticsExtension/Models/ConnectionStringValidator/BlobStorageValidator.cs index ce5feb15..59b662ed 100644 --- a/DiagnosticsExtension/Models/ConnectionStringValidator/BlobStorageValidator.cs +++ b/DiagnosticsExtension/Models/ConnectionStringValidator/BlobStorageValidator.cs @@ -15,6 +15,8 @@ using Azure.Storage.Queues; using Azure.Storage.Blobs.Models; using Microsoft.WindowsAzure.Storage; +using Azure.Core; +using Azure.Identity; namespace DiagnosticsExtension.Models.ConnectionStringValidator { @@ -25,13 +27,12 @@ public class BlobStorageValidator : IConnectionStringValidator public async Task ValidateViaAppsettingAsync(string appSettingName, string entityName) { ConnectionStringValidationResult response = new ConnectionStringValidationResult(Type); - + bool isManagedIdentityConnection = false; try { var envDict = Environment.GetEnvironmentVariables(); string appSettingClientIdValue, appSettingClientCredValue = null; BlobServiceClient client = null; - if (envDict.Contains(appSettingName)) { try @@ -50,43 +51,49 @@ public async Task ValidateViaAppsettingAsync(s } else { - string serviceUriString = ConnectionStringResponseUtility.ResolveManagedIdentityCommonProperty(appSettingName, ConnectionStringValidationResult.ManagedIdentityCommonProperty.blobServiceUri); + isManagedIdentityConnection = true; + string serviceUriString = ManagedIdentityConnectionResponseUtility.ResolveManagedIdentityCommonProperty(appSettingName, ConnectionStringValidationResult.ManagedIdentityCommonProperty.blobServiceUri); if (string.IsNullOrEmpty(serviceUriString)) { - serviceUriString = ConnectionStringResponseUtility.ResolveManagedIdentityCommonProperty(appSettingName, ConnectionStringValidationResult.ManagedIdentityCommonProperty.serviceUri); + serviceUriString = ManagedIdentityConnectionResponseUtility.ResolveManagedIdentityCommonProperty(appSettingName, ConnectionStringValidationResult.ManagedIdentityCommonProperty.serviceUri); } if (!string.IsNullOrEmpty(serviceUriString)) { - appSettingClientIdValue = ConnectionStringResponseUtility.ResolveManagedIdentityCommonProperty(appSettingName, ConnectionStringValidationResult.ManagedIdentityCommonProperty.clientId); - appSettingClientCredValue = ConnectionStringResponseUtility.ResolveManagedIdentityCommonProperty(appSettingName, ConnectionStringValidationResult.ManagedIdentityCommonProperty.credential); + appSettingClientIdValue = ManagedIdentityConnectionResponseUtility.ResolveManagedIdentityCommonProperty(appSettingName, ConnectionStringValidationResult.ManagedIdentityCommonProperty.clientId); + appSettingClientCredValue = ManagedIdentityConnectionResponseUtility.ResolveManagedIdentityCommonProperty(appSettingName, ConnectionStringValidationResult.ManagedIdentityCommonProperty.credential); Uri serviceUri = new Uri(serviceUriString); // Creating client using User assigned managed identity if (appSettingClientCredValue != null) { - if (appSettingClientCredValue != ConnectionStringResponseUtility.ValidCredentialValue) + if (appSettingClientCredValue != Constants.ValidCredentialValue) { - throw new ManagedIdentityException(ConnectionStringResponseUtility.ManagedIdentityCredentialInvalid); + throw new ManagedIdentityException(String.Format(Constants.ManagedIdentityCredentialInvalid, appSettingName)); } if (string.IsNullOrEmpty(appSettingClientIdValue)) { - throw new ManagedIdentityException(ConnectionStringResponseUtility.ManagedIdentityClientIdEmpty); + throw new ManagedIdentityException(String.Format(Constants.ManagedIdentityClientIdNullorEmpty, appSettingName)); } - response.IdentityType = ConnectionStringResponseUtility.User; - client = new BlobServiceClient(serviceUri, new Azure.Identity.ManagedIdentityCredential(appSettingClientIdValue)); + response.IdentityType = Constants.User; + client = new BlobServiceClient(serviceUri, new ManagedIdentityCredential(appSettingClientIdValue)); } // Creating client using System assigned managed identity else { - response.IdentityType = ConnectionStringResponseUtility.System; + response.IdentityType = Constants.System; client = new BlobServiceClient(serviceUri, new Azure.Identity.ManagedIdentityCredential()); } } else { - throw new ManagedIdentityException(ConnectionStringResponseUtility.ServiceUriMissing); + string serviceuriAppSettingName = Environment.GetEnvironmentVariables().Keys.Cast().Where(k => k.StartsWith(appSettingName) && k.ToLower().EndsWith("serviceuri")).FirstOrDefault(); + if (serviceuriAppSettingName == null) + { + throw new ManagedIdentityException(String.Format(Constants.BlobServiceUriMissing, appSettingName)); + } + throw new ManagedIdentityException(String.Format(Constants.BlobServiceUriEmpty, serviceuriAppSettingName)); + } } - client.GetBlobContainersAsync(); var resultSegment = client.GetBlobContainers(BlobContainerTraits.Metadata, null, default) .AsPages(default, 10); @@ -97,7 +104,14 @@ public async Task ValidateViaAppsettingAsync(s } catch (Exception e) { - ConnectionStringResponseUtility.EvaluateResponseStatus(e, Type, ref response); + if (isManagedIdentityConnection) + { + ManagedIdentityConnectionResponseUtility.EvaluateResponseStatus(e, Type, ref response, appSettingName); + } + else + { + ConnectionStringResponseUtility.EvaluateResponseStatus(e, Type, ref response, appSettingName); + } } return response; diff --git a/DiagnosticsExtension/Models/ConnectionStringValidator/ConnectionStringValidationResult.cs b/DiagnosticsExtension/Models/ConnectionStringValidator/ConnectionStringValidationResult.cs index b9a497dc..ec95ad69 100644 --- a/DiagnosticsExtension/Models/ConnectionStringValidator/ConnectionStringValidationResult.cs +++ b/DiagnosticsExtension/Models/ConnectionStringValidator/ConnectionStringValidationResult.cs @@ -17,6 +17,8 @@ public class ConnectionStringValidationResult { public ResultStatus? Status; public string IdentityType; + public string StatusSummary; + public string StatusDetails; public string StatusText => Status?.ToString(); public Exception Exception; public object Payload; @@ -42,20 +44,16 @@ public enum ResultStatus EmptyConnectionString, MalformedConnectionString, ManagedIdentityCredentialInvalid, - ManagedIdentityClientIdEmpty, + ManagedIdentityClientIdNullorEmpty, FullyQualifiedNamespaceMissing, SystemAssignedIdentityFailure, UserAssignedIdentityFailure, ManagedIdentityNotConfigured, ManagedIdentityAuthFailure, ServiceUriMissing, + ManagedIdentityConnectionFailed, UnknownError, } - public enum ManagedIdentityType - { - User, - System - } public enum ManagedIdentityCommonProperty { fullyQualifiedNamespace, diff --git a/DiagnosticsExtension/Models/ConnectionStringValidator/Constants.cs b/DiagnosticsExtension/Models/ConnectionStringValidator/Constants.cs new file mode 100644 index 00000000..8c77e54f --- /dev/null +++ b/DiagnosticsExtension/Models/ConnectionStringValidator/Constants.cs @@ -0,0 +1,52 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. +// +// ----------------------------------------------------------------------- + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Web; + +namespace DiagnosticsExtension.Models.ConnectionStringValidator +{ + public static class Constants + { + #region string constants for network validator + public const string User = "User"; + public const string System = "System"; + public const string UnderscoreSeperator = "__"; + public const string ColonSeparator = ":"; + public const string ClientId = "__clientId"; + public const string Credential = "__credential"; + public const string ServiceUri = "__serviceUri"; + public const string BlobServiceUri = "__blobServiceUri"; + public const string BlobServiceUriMissing = "Neither {0}__blobServiceUri nor {0}__serviceUri app settings were found. Click here to know more"; + public const string BlobServiceUriEmpty = "{0} app setting is empty. Click here to know more"; + public const string ServiceUriEmpty = "ServiceUriEmpty"; + public const string QueueServiceUriMissing = "The {0}__queueServiceUri was not found or is set to a blank value. Click here to know more"; + public const string QueueServiceUri = "__queueServiceUri"; + public const string ValidCredentialValue = "managedidentity"; + public const string FullyQualifiedNamespace = "__fullyQualifiedNamespace"; + public const string ManagedIdentityClientIdNullorEmpty = "The {0}__clientId was not found or is set to a blank value. Click here to know more"; + public const string AuthorizationFailure = "Authorization failure"; + public const string AuthenticationFailure = "Authentication failure"; + public const string ConnectionInformation = "Necessary connection information was not found"; + public const string InvalidConnection = "Invalid connection string"; + public const string ResourceNotFound = "Resource not found"; + public const string DetailsHeader = "Please see exception below. "; + public const string ClientIdInvalidTokenGeneratedResponse = "ClientIdInvalidTokenGeneratedResponse"; + public const string ClientIdInvalidTokenGenerated = "An invalid clientId has been provided in {0}__clientId. But managed identity connection was attempted becasuse function app has system assigned identity turned on. "; + public const string SystemAssignedAuthFailure = "The azure resource mentioned in {0} is not provided with access to the function app using system assigned identity. Click here to know more"; + public const string UserAssignedAuthFailure = "The azure resource mentioned in {0} is not provided with access to the managed identity resource having clientId specified in appsetting {1}__clientId . Click here to know more"; + public const string AuthFailureDetails = "Authentication failure -the credentials in the configured connection string are either invalid or expired. Please update the app setting with a valid connection string."; + public const string DnsLookupFailedDetails = "The service resource specified in the connection string was not found. Please check the value of the setting."; + public const string FQNamespaceResourceNotFound = "The resource specified in the app setting {0}__fullyQualifiedNamespace was not found. Please check the value of the setting."; + public const string StorageAccountResourceNotFound = "The resource specified in the app setting {0} was not found. Please check the value of the setting."; + public const string MalformedConnectionStringDetails = "The connection string configured is invalid(e.g.missing some required elements). Please check the value configured in the app setting "; + public const string ManagedIdentityCredentialInvalid = "The {0}__credential was not set to 'managedidentity'. Click here to know more"; + #endregion + } +} diff --git a/DiagnosticsExtension/Models/ConnectionStringValidator/EventHubsValidator.cs b/DiagnosticsExtension/Models/ConnectionStringValidator/EventHubsValidator.cs index b053990c..91269adc 100644 --- a/DiagnosticsExtension/Models/ConnectionStringValidator/EventHubsValidator.cs +++ b/DiagnosticsExtension/Models/ConnectionStringValidator/EventHubsValidator.cs @@ -74,7 +74,7 @@ protected async Task TestConnectionStringAsync(string connec async public Task ValidateViaAppsettingAsync(string appSettingName, string entityName) { ConnectionStringValidationResult response = new ConnectionStringValidationResult(Type); - + bool isManagedIdentityConnection = false; try { string appSettingClientIdValue, appSettingClientCredValue = ""; @@ -97,35 +97,29 @@ async public Task ValidateViaAppsettingAsync(s } else { - try + isManagedIdentityConnection = true; + string serviceUriString = ManagedIdentityConnectionResponseUtility.ResolveManagedIdentityCommonProperty(appSettingName, ConnectionStringValidationResult.ManagedIdentityCommonProperty.fullyQualifiedNamespace); + appSettingClientIdValue = ManagedIdentityConnectionResponseUtility.ResolveManagedIdentityCommonProperty(appSettingName, ConnectionStringValidationResult.ManagedIdentityCommonProperty.clientId); + appSettingClientCredValue = ManagedIdentityConnectionResponseUtility.ResolveManagedIdentityCommonProperty(appSettingName, ConnectionStringValidationResult.ManagedIdentityCommonProperty.credential); + // Creating client using User assigned managed identity + if (appSettingClientCredValue != null) { - string serviceUriString = ConnectionStringResponseUtility.ResolveManagedIdentityCommonProperty(appSettingName, ConnectionStringValidationResult.ManagedIdentityCommonProperty.fullyQualifiedNamespace); - appSettingClientIdValue = ConnectionStringResponseUtility.ResolveManagedIdentityCommonProperty(appSettingName, ConnectionStringValidationResult.ManagedIdentityCommonProperty.clientId); - appSettingClientCredValue = ConnectionStringResponseUtility.ResolveManagedIdentityCommonProperty(appSettingName, ConnectionStringValidationResult.ManagedIdentityCommonProperty.credential); - // Creating client using User assigned managed identity - if (appSettingClientCredValue != null) + if (appSettingClientCredValue != Constants.ValidCredentialValue) { - if (appSettingClientCredValue != ConnectionStringResponseUtility.ValidCredentialValue) - { - throw new ManagedIdentityException(ConnectionStringResponseUtility.ManagedIdentityCredentialInvalid); - } - if (string.IsNullOrEmpty(appSettingClientIdValue)) - { - throw new ManagedIdentityException(ConnectionStringResponseUtility.ManagedIdentityClientIdEmpty); - } - response.IdentityType = ConnectionStringResponseUtility.User; - client = new EventHubProducerClient(serviceUriString, eventHubName, new ManagedIdentityCredential(appSettingClientIdValue)); + throw new ManagedIdentityException(String.Format(Constants.ManagedIdentityCredentialInvalid, appSettingName)); } - // Creating client using System assigned managed identity - else + if (string.IsNullOrEmpty(appSettingClientIdValue)) { - response.IdentityType = ConnectionStringResponseUtility.System; - client = new EventHubProducerClient(serviceUriString, eventHubName, new ManagedIdentityCredential()); + throw new ManagedIdentityException(String.Format(Constants.ManagedIdentityClientIdNullorEmpty, appSettingName)); } + response.IdentityType = Constants.User; + client = new EventHubProducerClient(serviceUriString, eventHubName, new ManagedIdentityCredential(appSettingClientIdValue)); } - catch (Exception e) + // Creating client using System assigned managed identity + else { - throw new ManagedIdentityException(e.Message, e); + response.IdentityType = Constants.System; + client = new EventHubProducerClient(serviceUriString, eventHubName, new ManagedIdentityCredential()); } } await client.GetPartitionIdsAsync(); @@ -135,7 +129,14 @@ async public Task ValidateViaAppsettingAsync(s } catch (Exception e) { - ConnectionStringResponseUtility.EvaluateResponseStatus(e, Type, ref response); + if (isManagedIdentityConnection) + { + ManagedIdentityConnectionResponseUtility.EvaluateResponseStatus(e, Type, ref response, appSettingName); + } + else + { + ConnectionStringResponseUtility.EvaluateResponseStatus(e, Type, ref response, appSettingName); + } } return response; diff --git a/DiagnosticsExtension/Models/ConnectionStringValidator/Exceptions/ConnectionStringResponseUtility.cs b/DiagnosticsExtension/Models/ConnectionStringValidator/Exceptions/ConnectionStringResponseUtility.cs index 0eced0b5..a505c7ec 100644 --- a/DiagnosticsExtension/Models/ConnectionStringValidator/Exceptions/ConnectionStringResponseUtility.cs +++ b/DiagnosticsExtension/Models/ConnectionStringValidator/Exceptions/ConnectionStringResponseUtility.cs @@ -17,83 +17,60 @@ namespace DiagnosticsExtension.Models.ConnectionStringValidator.Exceptions { public static class ConnectionStringResponseUtility { - #region string constants for network validator - public const string User = "User"; - public const string System = "System"; - public const string UnderscoreSeperator = "__"; - public const string ColonSeparator = ":"; - public const string ClientId = "__clientId"; - public const string Credential = "__credential"; - public const string ServiceUri = "__serviceUri"; - public const string BlobServiceUri = "__blobServiceUri"; - public const string ServiceUriMissing = "ServiceUriMissing"; - public const string QueueServiceUri = "__queueServiceUri"; - public const string ValidCredentialValue = "managedidentity"; - public const string FullyQualifiedNamespace = "__fullyQualifiedNamespace"; - public const string ManagedIdentityClientIdEmpty = "ManagedIdentityClientIdEmpty"; - public const string ManagedIdentityCredentialInvalid = "ManagedIdentityCredentialInvalid"; - #endregion - - public static void EvaluateResponseStatus(Exception e, ConnectionStringType type, ref ConnectionStringValidationResult response) + public static void EvaluateResponseStatus(Exception e, ConnectionStringType type, ref ConnectionStringValidationResult response, string appSettingName = "") { if (e is MalformedConnectionStringException) { response.Status = ConnectionStringValidationResult.ResultStatus.MalformedConnectionString; + response.StatusSummary = Constants.InvalidConnection; + response.StatusDetails = Constants.MalformedConnectionStringDetails + appSettingName; + response.Exception = e; } else if (e is EmptyConnectionStringException) { response.Status = ConnectionStringValidationResult.ResultStatus.EmptyConnectionString; - } - else if (e is ManagedIdentityException && e.Message.Contains(ManagedIdentityCredentialInvalid)) - { - response.Status = ConnectionStringValidationResult.ResultStatus.ManagedIdentityCredentialInvalid; - } - else if (e is ManagedIdentityException && e.Message.Contains(ManagedIdentityClientIdEmpty)) - { - response.Status = ConnectionStringValidationResult.ResultStatus.ManagedIdentityClientIdEmpty; + response.StatusSummary = "The app setting " + appSettingName + " was not found or is set to a blank value"; + response.Exception = e; } else if (e is UnauthorizedAccessException && e.Message.Contains("unauthorized") || e.Message.Contains("Unauthorized") || e.Message.Contains("request is not authorized")) { - if (string.IsNullOrEmpty(response.IdentityType)) - { - response.Status = ConnectionStringValidationResult.ResultStatus.AuthFailure; - } - else - { - response.Status = ConnectionStringValidationResult.ResultStatus.ManagedIdentityAuthFailure; - } - } - else if (e is AuthenticationFailedException && e.Message.Contains("ManagedIdentityCredential")) - { - response.Status = ConnectionStringValidationResult.ResultStatus.ManagedIdentityNotConfigured; - } - else if (e.Message.Contains("fullyQualifiedNamespace")) - { - response.Status = ConnectionStringValidationResult.ResultStatus.FullyQualifiedNamespaceMissing; - } - else if (e is ManagedIdentityException && e.Message.Contains("ServiceUriMissing")) - { - response.Status = ConnectionStringValidationResult.ResultStatus.ServiceUriMissing; + response.Status = ConnectionStringValidationResult.ResultStatus.AuthFailure; + response.StatusSummary = Constants.AuthenticationFailure; + response.StatusDetails = Constants.AuthFailureDetails; + + response.Exception = e; } else if (e.InnerException != null && e.InnerException.Message.Contains("The remote name could not be resolved")) { response.Status = ConnectionStringValidationResult.ResultStatus.DnsLookupFailed; + response.StatusSummary = Constants.ResourceNotFound; + response.StatusDetails = Constants.DnsLookupFailedDetails; + response.Exception = e; } else if (e.InnerException != null && e.InnerException.InnerException != null && e.InnerException.InnerException.Message.Contains("The remote name could not be resolved")) { response.Status = ConnectionStringValidationResult.ResultStatus.DnsLookupFailed; + response.StatusSummary = Constants.ResourceNotFound; + response.StatusDetails = Constants.DnsLookupFailedDetails; + response.Exception = e; } else if (e.Message.Contains("No such host is known")) { response.Status = ConnectionStringValidationResult.ResultStatus.DnsLookupFailed; + response.StatusSummary = Constants.ResourceNotFound; + response.StatusDetails = Constants.DnsLookupFailedDetails; + response.Exception = e; } else if (e is ArgumentNullException || e.Message.Contains("could not be found") || e.Message.Contains("was not found")) { response.Status = ConnectionStringValidationResult.ResultStatus.MalformedConnectionString; + response.StatusSummary = Constants.InvalidConnection; + response.StatusDetails = Constants.MalformedConnectionStringDetails; + response.Exception = e; } else if (e is ArgumentException && e.Message.Contains("entityPath is null") || e.Message.Contains("HostNotFound") || @@ -101,46 +78,50 @@ public static void EvaluateResponseStatus(Exception e, ConnectionStringType type e.Message.Contains("The argument is null or white space")) { response.Status = ConnectionStringValidationResult.ResultStatus.MalformedConnectionString; + response.StatusSummary = Constants.InvalidConnection; + response.StatusDetails = Constants.MalformedConnectionStringDetails; + response.Exception = e; } else if (e.Message.Contains("InvalidSignature")) { response.Status = ConnectionStringValidationResult.ResultStatus.AuthFailure; + response.StatusSummary = Constants.AuthenticationFailure; + response.StatusDetails = Constants.AuthFailureDetails; + response.Exception = e; } else if ((e is ArgumentException && e.Message.Contains("Authentication")) || e.Message.Contains("claim is empty or token is invalid") || e.Message.Contains("InvalidSignature")) { response.Status = ConnectionStringValidationResult.ResultStatus.AuthFailure; + response.StatusSummary = Constants.AuthenticationFailure; + response.StatusDetails = Constants.AuthFailureDetails; + response.Exception = e; } else if (e.Message.Contains("Ip has been prevented to connect to the endpoint")) { response.Status = ConnectionStringValidationResult.ResultStatus.Forbidden; + response.Exception = e; } else if (e is StorageException) { if (((StorageException)e).RequestInformation.HttpStatusCode == 401) { response.Status = ConnectionStringValidationResult.ResultStatus.AuthFailure; + response.StatusSummary = Constants.AuthenticationFailure; + response.StatusDetails = Constants.AuthFailureDetails; } else if (((StorageException)e).RequestInformation.HttpStatusCode == 403) { response.Status = ConnectionStringValidationResult.ResultStatus.Forbidden; } + response.Exception = e; } else { response.Status = ConnectionStringValidationResult.ResultStatus.UnknownError; } - response.Exception = e; - } - public static string ResolveManagedIdentityCommonProperty(string appSettingName, ConnectionStringValidationResult.ManagedIdentityCommonProperty prop) - { - string commonPropertyValue = Environment.GetEnvironmentVariable(appSettingName + UnderscoreSeperator + prop.ToString()); - if (string.IsNullOrEmpty(commonPropertyValue)) - { - commonPropertyValue = Environment.GetEnvironmentVariable(appSettingName + ColonSeparator + prop.ToString()); - } - return commonPropertyValue; } + } } diff --git a/DiagnosticsExtension/Models/ConnectionStringValidator/Exceptions/ManagedIdentityConnectionResponseUtility.cs b/DiagnosticsExtension/Models/ConnectionStringValidator/Exceptions/ManagedIdentityConnectionResponseUtility.cs new file mode 100644 index 00000000..e08cee10 --- /dev/null +++ b/DiagnosticsExtension/Models/ConnectionStringValidator/Exceptions/ManagedIdentityConnectionResponseUtility.cs @@ -0,0 +1,103 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. +// +// ----------------------------------------------------------------------- + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Web; +using Azure; +using Azure.Identity; +using Microsoft.WindowsAzure.Storage; + +namespace DiagnosticsExtension.Models.ConnectionStringValidator.Exceptions +{ + public static class ManagedIdentityConnectionResponseUtility + { + public static void EvaluateResponseStatus(Exception e, ConnectionStringType type, ref ConnectionStringValidationResult response, string appSettingName = "") + { + if (e is ManagedIdentityException) + { + response.Status = ConnectionStringValidationResult.ResultStatus.ManagedIdentityConnectionFailed; + response.StatusSummary = Constants.ConnectionInformation; + response.StatusDetails = Constants.DetailsHeader; + response.Exception = e; + } + else if (e is UnauthorizedAccessException && e.Message.Contains("unauthorized") || e.Message.Contains("Unauthorized") || e.Message.Contains("request is not authorized")) + { + response.Status = ConnectionStringValidationResult.ResultStatus.ManagedIdentityAuthFailure; + response.StatusSummary = Constants.AuthorizationFailure; + if (response.IdentityType == "System") + { + response.StatusDetails = String.Format(Constants.SystemAssignedAuthFailure, GetTargetConnectionAppSettingName(type, appSettingName)); + } + else + { + response.StatusDetails = String.Format(Constants.UserAssignedAuthFailure, GetTargetConnectionAppSettingName(type, appSettingName), appSettingName); + } + + response.Exception = e; + } + else if (e is AuthenticationFailedException && e.Message.Contains("ManagedIdentityCredential")) + { + response.Status = ConnectionStringValidationResult.ResultStatus.ManagedIdentityNotConfigured; + response.StatusSummary = "Your app is not having managed identity configured for making a successful connection. Click here to know more"; + response.Exception = e; + } + else if (e.Message.Contains("fullyQualifiedNamespace")) + { + response.Status = ConnectionStringValidationResult.ResultStatus.FullyQualifiedNamespaceMissing; + response.StatusSummary = "The app setting " + appSettingName + "__fullyQualifiedNamespace was not found or is set to a blank value Click here to know more"; + response.Exception = e; + } + else if (e.InnerException != null && + e.InnerException.Message.Contains("The remote name could not be resolved")) // queue and blob + { + + response.Status = ConnectionStringValidationResult.ResultStatus.DnsLookupFailed; + response.StatusSummary = Constants.ResourceNotFound; + response.StatusDetails = String.Format(Constants.StorageAccountResourceNotFound, GetTargetConnectionAppSettingName(type, appSettingName)); + response.Exception = e; + } + else if (e.Message.Contains("No such host is known")) // event hub and service bus + { + response.Status = ConnectionStringValidationResult.ResultStatus.DnsLookupFailed; + response.StatusSummary = Constants.ResourceNotFound; + response.StatusDetails = String.Format(Constants.FQNamespaceResourceNotFound, appSettingName); + response.Exception = e; + } + } + public static string ResolveManagedIdentityCommonProperty(string appSettingName, ConnectionStringValidationResult.ManagedIdentityCommonProperty prop) + { + string commonPropertyValue = Environment.GetEnvironmentVariable(appSettingName + Constants.UnderscoreSeperator + prop.ToString()); + + if (commonPropertyValue == null) + { + commonPropertyValue = Environment.GetEnvironmentVariable(appSettingName + Constants.ColonSeparator + prop.ToString()); + } + return commonPropertyValue; + } + public static string GetTargetConnectionAppSettingName(ConnectionStringType type, string appSettingName) + { + string serviceuriAppSettingName = ""; + switch (type) + { + + case ConnectionStringType.ServiceBus: + case ConnectionStringType.EventHubs: + serviceuriAppSettingName = Environment.GetEnvironmentVariables().Keys.Cast().Where(k => k.StartsWith(appSettingName) && k.ToLower().EndsWith("fullyqualifiednamespace")).FirstOrDefault(); + + break; + case ConnectionStringType.BlobStorageAccount: + case ConnectionStringType.QueueStorageAccount: + serviceuriAppSettingName = Environment.GetEnvironmentVariables().Keys.Cast().Where(k => k.StartsWith(appSettingName) && k.ToLower().EndsWith("serviceuri")).FirstOrDefault(); + + break; + } + return serviceuriAppSettingName; + } + } +} diff --git a/DiagnosticsExtension/Models/ConnectionStringValidator/ManagedIdentityCredentialTokenValidator.cs b/DiagnosticsExtension/Models/ConnectionStringValidator/ManagedIdentityCredentialTokenValidator.cs new file mode 100644 index 00000000..b2ad014e --- /dev/null +++ b/DiagnosticsExtension/Models/ConnectionStringValidator/ManagedIdentityCredentialTokenValidator.cs @@ -0,0 +1,41 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. +// +// ----------------------------------------------------------------------- + +using System; +using System.Collections.Generic; +using System.IdentityModel.Tokens.Jwt; +using System.Linq; +using System.Web; +using Azure.Core; +using Azure.Identity; +using DiagnosticsExtension.Models.ConnectionStringValidator.Exceptions; + +namespace DiagnosticsExtension.Models.ConnectionStringValidator +{ + public static class ManagedIdentityCredentialTokenValidator + { + public static ManagedIdentityCredential GetValidatedCredential(string clientId) + { + var tokenCredential = new ManagedIdentityCredential(clientId); + + var accessToken = tokenCredential.GetTokenAsync(new TokenRequestContext(scopes: new string[] { "https://storage.azure.com/.default" }) { }); + + JwtSecurityTokenHandler jwtHandler = new JwtSecurityTokenHandler(); + + string appId = jwtHandler.ReadJwtToken(accessToken.Result.Token).Claims.ToList().Where(c => c.Type == "appid").FirstOrDefault().Value; + + if(clientId != "" && appId != clientId) + { + throw new ManagedIdentityException(Constants.ClientIdInvalidTokenGeneratedResponse); + } + + return tokenCredential; + } + + } + +} diff --git a/DiagnosticsExtension/Models/ConnectionStringValidator/QueueStorageValidator.cs b/DiagnosticsExtension/Models/ConnectionStringValidator/QueueStorageValidator.cs index 16159239..4c15f543 100644 --- a/DiagnosticsExtension/Models/ConnectionStringValidator/QueueStorageValidator.cs +++ b/DiagnosticsExtension/Models/ConnectionStringValidator/QueueStorageValidator.cs @@ -26,7 +26,7 @@ public class QueueStorageValidator : IConnectionStringValidator public async Task ValidateViaAppsettingAsync(string appSettingName, string entityName) { ConnectionStringValidationResult response = new ConnectionStringValidationResult(Type); - + bool isManagedIdentityConnection = false; try { var envDict = Environment.GetEnvironmentVariables(); @@ -51,39 +51,40 @@ public async Task ValidateViaAppsettingAsync(s } else { - string serviceUriString = ConnectionStringResponseUtility.ResolveManagedIdentityCommonProperty(appSettingName, ConnectionStringValidationResult.ManagedIdentityCommonProperty.queueServiceUri); + isManagedIdentityConnection = true; + string serviceUriString = ManagedIdentityConnectionResponseUtility.ResolveManagedIdentityCommonProperty(appSettingName, ConnectionStringValidationResult.ManagedIdentityCommonProperty.queueServiceUri); if (!string.IsNullOrEmpty(serviceUriString)) { - appSettingClientIdValue = ConnectionStringResponseUtility.ResolveManagedIdentityCommonProperty(appSettingName, ConnectionStringValidationResult.ManagedIdentityCommonProperty.clientId); - appSettingClientCredValue = ConnectionStringResponseUtility.ResolveManagedIdentityCommonProperty(appSettingName, ConnectionStringValidationResult.ManagedIdentityCommonProperty.credential); + appSettingClientIdValue = ManagedIdentityConnectionResponseUtility.ResolveManagedIdentityCommonProperty(appSettingName, ConnectionStringValidationResult.ManagedIdentityCommonProperty.clientId); + appSettingClientCredValue = ManagedIdentityConnectionResponseUtility.ResolveManagedIdentityCommonProperty(appSettingName, ConnectionStringValidationResult.ManagedIdentityCommonProperty.credential); Uri serviceUri = new Uri(serviceUriString); // Creating client using User assigned managed identity if (appSettingClientCredValue != null) { - if (appSettingClientCredValue != ConnectionStringResponseUtility.ValidCredentialValue) + if (appSettingClientCredValue != Constants.ValidCredentialValue) { - throw new ManagedIdentityException(ConnectionStringResponseUtility.ManagedIdentityCredentialInvalid); + throw new ManagedIdentityException(String.Format(Constants.ManagedIdentityCredentialInvalid, appSettingName)); } if (string.IsNullOrEmpty(appSettingClientIdValue)) { - throw new ManagedIdentityException(ConnectionStringResponseUtility.ManagedIdentityClientIdEmpty); + throw new ManagedIdentityException(String.Format(Constants.ManagedIdentityClientIdNullorEmpty, appSettingName)); } - response.IdentityType = ConnectionStringResponseUtility.User; + response.IdentityType = Constants.User; client = new QueueServiceClient(serviceUri, new Azure.Identity.ManagedIdentityCredential(appSettingClientIdValue)); } // Creating client using System assigned managed identity else { - response.IdentityType = ConnectionStringResponseUtility.System; + response.IdentityType = Constants.System; client = new QueueServiceClient(serviceUri, new Azure.Identity.ManagedIdentityCredential()); } } else { - throw new ManagedIdentityException(ConnectionStringResponseUtility.ServiceUriMissing); + throw new ManagedIdentityException(String.Format(Constants.QueueServiceUriMissing, appSettingName)); } } - client.GetQueuesAsync(); + //client.GetQueuesAsync(); var resultSegment = client.GetQueues(QueueTraits.Metadata, null, default) .AsPages(default, 10); @@ -98,7 +99,14 @@ public async Task ValidateViaAppsettingAsync(s } catch (Exception e) { - ConnectionStringResponseUtility.EvaluateResponseStatus(e, Type, ref response); + if (isManagedIdentityConnection) + { + ManagedIdentityConnectionResponseUtility.EvaluateResponseStatus(e, Type, ref response, appSettingName); + } + else + { + ConnectionStringResponseUtility.EvaluateResponseStatus(e, Type, ref response, appSettingName); + } } return response; diff --git a/DiagnosticsExtension/Models/ConnectionStringValidator/ServiceBusValidator.cs b/DiagnosticsExtension/Models/ConnectionStringValidator/ServiceBusValidator.cs index b32dc0f9..7a2dbbf2 100644 --- a/DiagnosticsExtension/Models/ConnectionStringValidator/ServiceBusValidator.cs +++ b/DiagnosticsExtension/Models/ConnectionStringValidator/ServiceBusValidator.cs @@ -89,7 +89,7 @@ protected async Task TestConnectionStringAsync(string connec async public Task ValidateViaAppsettingAsync(string appSettingName, string entityName) { ConnectionStringValidationResult response = new ConnectionStringValidationResult(Type); - + bool isManagedIdentityConnection = false; try { string appSettingClientIdValue, appSettingClientCredValue = ""; @@ -111,27 +111,28 @@ async public Task ValidateViaAppsettingAsync(s } else { - string serviceUriString = ConnectionStringResponseUtility.ResolveManagedIdentityCommonProperty(appSettingName, ConnectionStringValidationResult.ManagedIdentityCommonProperty.fullyQualifiedNamespace); - appSettingClientIdValue = ConnectionStringResponseUtility.ResolveManagedIdentityCommonProperty(appSettingName, ConnectionStringValidationResult.ManagedIdentityCommonProperty.clientId); - appSettingClientCredValue = ConnectionStringResponseUtility.ResolveManagedIdentityCommonProperty(appSettingName, ConnectionStringValidationResult.ManagedIdentityCommonProperty.credential); + isManagedIdentityConnection = true; + string serviceUriString = ManagedIdentityConnectionResponseUtility.ResolveManagedIdentityCommonProperty(appSettingName, ConnectionStringValidationResult.ManagedIdentityCommonProperty.fullyQualifiedNamespace); + appSettingClientIdValue = ManagedIdentityConnectionResponseUtility.ResolveManagedIdentityCommonProperty(appSettingName, ConnectionStringValidationResult.ManagedIdentityCommonProperty.clientId); + appSettingClientCredValue = ManagedIdentityConnectionResponseUtility.ResolveManagedIdentityCommonProperty(appSettingName, ConnectionStringValidationResult.ManagedIdentityCommonProperty.credential); // Creating client using User assigned managed identity if (appSettingClientCredValue != null) { - if (appSettingClientCredValue != ConnectionStringResponseUtility.ValidCredentialValue) + if (appSettingClientCredValue != Constants.ValidCredentialValue) { - throw new ManagedIdentityException(ConnectionStringResponseUtility.ManagedIdentityCredentialInvalid); + throw new ManagedIdentityException(String.Format(Constants.ManagedIdentityCredentialInvalid, appSettingName)); } if (string.IsNullOrEmpty(appSettingClientIdValue)) { - throw new ManagedIdentityException(ConnectionStringResponseUtility.ManagedIdentityClientIdEmpty); + throw new ManagedIdentityException(String.Format(Constants.ManagedIdentityClientIdNullorEmpty, appSettingName)); } - response.IdentityType = ConnectionStringResponseUtility.User; + response.IdentityType = Constants.User; client = new ServiceBusClient(serviceUriString, new Azure.Identity.ManagedIdentityCredential(appSettingClientIdValue)); } // Creating client using System assigned managed identity else { - response.IdentityType = ConnectionStringResponseUtility.System; + response.IdentityType = Constants.System; client = new ServiceBusClient(serviceUriString, new Azure.Identity.ManagedIdentityCredential()); } } @@ -145,7 +146,14 @@ async public Task ValidateViaAppsettingAsync(s } catch (Exception e) { - ConnectionStringResponseUtility.EvaluateResponseStatus(e, Type, ref response); + if (isManagedIdentityConnection) + { + ManagedIdentityConnectionResponseUtility.EvaluateResponseStatus(e, Type, ref response, appSettingName); + } + else + { + ConnectionStringResponseUtility.EvaluateResponseStatus(e, Type, ref response, appSettingName); + } } return response; From 062c3a335d5f14e7b4b968d672379a0356df9f74 Mon Sep 17 00:00:00 2001 From: Gajibilli Koteswara Rao Date: Thu, 24 Mar 2022 23:11:56 +0530 Subject: [PATCH 10/26] Removed ommented code --- .../Models/ConnectionStringValidator/QueueStorageValidator.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/DiagnosticsExtension/Models/ConnectionStringValidator/QueueStorageValidator.cs b/DiagnosticsExtension/Models/ConnectionStringValidator/QueueStorageValidator.cs index 4c15f543..d2273d53 100644 --- a/DiagnosticsExtension/Models/ConnectionStringValidator/QueueStorageValidator.cs +++ b/DiagnosticsExtension/Models/ConnectionStringValidator/QueueStorageValidator.cs @@ -84,7 +84,6 @@ public async Task ValidateViaAppsettingAsync(s throw new ManagedIdentityException(String.Format(Constants.QueueServiceUriMissing, appSettingName)); } } - //client.GetQueuesAsync(); var resultSegment = client.GetQueues(QueueTraits.Metadata, null, default) .AsPages(default, 10); From db7a575e044f0356f98578a26c90de011d85f907 Mon Sep 17 00:00:00 2001 From: Gajibilli Koteswara Rao Date: Fri, 25 Mar 2022 21:26:18 +0530 Subject: [PATCH 11/26] jwt Token related code changes --- DiagnosticsExtension/DiagnosticsExtension.csproj | 16 ++++++++-------- .../BlobStorageValidator.cs | 2 +- .../ConnectionStringValidationResult.cs | 5 ----- .../ConnectionStringValidator/Constants.cs | 3 +-- .../EventHubsValidator.cs | 2 +- .../ManagedIdentityCredentialTokenValidator.cs | 8 ++++---- .../QueueStorageValidator.cs | 2 +- .../ServiceBusValidator.cs | 2 +- DiagnosticsExtension/Web.config | 6 +++++- DiagnosticsExtension/packages.config | 8 ++++---- 10 files changed, 26 insertions(+), 28 deletions(-) diff --git a/DiagnosticsExtension/DiagnosticsExtension.csproj b/DiagnosticsExtension/DiagnosticsExtension.csproj index b4f9ccf5..305da98c 100644 --- a/DiagnosticsExtension/DiagnosticsExtension.csproj +++ b/DiagnosticsExtension/DiagnosticsExtension.csproj @@ -132,14 +132,14 @@ ..\packages\Microsoft.IdentityModel.Clients.ActiveDirectory.4.5.0\lib\net45\Microsoft.IdentityModel.Clients.ActiveDirectory.dll - - ..\packages\Microsoft.IdentityModel.JsonWebTokens.5.4.0\lib\net461\Microsoft.IdentityModel.JsonWebTokens.dll + + ..\packages\Microsoft.IdentityModel.JsonWebTokens.6.10.0\lib\net472\Microsoft.IdentityModel.JsonWebTokens.dll - - ..\packages\Microsoft.IdentityModel.Logging.5.4.0\lib\net461\Microsoft.IdentityModel.Logging.dll + + ..\packages\Microsoft.IdentityModel.Logging.6.10.0\lib\net472\Microsoft.IdentityModel.Logging.dll - - ..\packages\Microsoft.IdentityModel.Tokens.5.4.0\lib\net461\Microsoft.IdentityModel.Tokens.dll + + ..\packages\Microsoft.IdentityModel.Tokens.6.10.0\lib\net472\Microsoft.IdentityModel.Tokens.dll ..\packages\CommonServiceLocator.1.3\lib\portable-net4+sl5+netcore45+wpa81+wp8\Microsoft.Practices.ServiceLocation.dll @@ -182,8 +182,8 @@ - - ..\packages\System.IdentityModel.Tokens.Jwt.5.4.0\lib\net461\System.IdentityModel.Tokens.Jwt.dll + + ..\packages\System.IdentityModel.Tokens.Jwt.6.10.0\lib\net472\System.IdentityModel.Tokens.Jwt.dll ..\packages\System.IO.4.3.0\lib\net462\System.IO.dll diff --git a/DiagnosticsExtension/Models/ConnectionStringValidator/BlobStorageValidator.cs b/DiagnosticsExtension/Models/ConnectionStringValidator/BlobStorageValidator.cs index 59b662ed..f49e2281 100644 --- a/DiagnosticsExtension/Models/ConnectionStringValidator/BlobStorageValidator.cs +++ b/DiagnosticsExtension/Models/ConnectionStringValidator/BlobStorageValidator.cs @@ -74,7 +74,7 @@ public async Task ValidateViaAppsettingAsync(s throw new ManagedIdentityException(String.Format(Constants.ManagedIdentityClientIdNullorEmpty, appSettingName)); } response.IdentityType = Constants.User; - client = new BlobServiceClient(serviceUri, new ManagedIdentityCredential(appSettingClientIdValue)); + client = new BlobServiceClient(serviceUri, ManagedIdentityCredentialTokenValidator.GetValidatedCredential(appSettingClientIdValue,appSettingName)); } // Creating client using System assigned managed identity else diff --git a/DiagnosticsExtension/Models/ConnectionStringValidator/ConnectionStringValidationResult.cs b/DiagnosticsExtension/Models/ConnectionStringValidator/ConnectionStringValidationResult.cs index ec95ad69..7cf67b53 100644 --- a/DiagnosticsExtension/Models/ConnectionStringValidator/ConnectionStringValidationResult.cs +++ b/DiagnosticsExtension/Models/ConnectionStringValidator/ConnectionStringValidationResult.cs @@ -43,14 +43,9 @@ public enum ResultStatus MsiFailure, EmptyConnectionString, MalformedConnectionString, - ManagedIdentityCredentialInvalid, - ManagedIdentityClientIdNullorEmpty, FullyQualifiedNamespaceMissing, - SystemAssignedIdentityFailure, - UserAssignedIdentityFailure, ManagedIdentityNotConfigured, ManagedIdentityAuthFailure, - ServiceUriMissing, ManagedIdentityConnectionFailed, UnknownError, } diff --git a/DiagnosticsExtension/Models/ConnectionStringValidator/Constants.cs b/DiagnosticsExtension/Models/ConnectionStringValidator/Constants.cs index 8c77e54f..dc9449a6 100644 --- a/DiagnosticsExtension/Models/ConnectionStringValidator/Constants.cs +++ b/DiagnosticsExtension/Models/ConnectionStringValidator/Constants.cs @@ -37,8 +37,7 @@ public static class Constants public const string InvalidConnection = "Invalid connection string"; public const string ResourceNotFound = "Resource not found"; public const string DetailsHeader = "Please see exception below. "; - public const string ClientIdInvalidTokenGeneratedResponse = "ClientIdInvalidTokenGeneratedResponse"; - public const string ClientIdInvalidTokenGenerated = "An invalid clientId has been provided in {0}__clientId. But managed identity connection was attempted becasuse function app has system assigned identity turned on. "; + public const string ClientIdInvalidTokenGenerated = "An invalid clientId has been provided in {0}__clientId. But managed identity connection was attempted because function app has system assigned identity turned on. "; public const string SystemAssignedAuthFailure = "The azure resource mentioned in {0} is not provided with access to the function app using system assigned identity. Click here to know more"; public const string UserAssignedAuthFailure = "The azure resource mentioned in {0} is not provided with access to the managed identity resource having clientId specified in appsetting {1}__clientId . Click here to know more"; public const string AuthFailureDetails = "Authentication failure -the credentials in the configured connection string are either invalid or expired. Please update the app setting with a valid connection string."; diff --git a/DiagnosticsExtension/Models/ConnectionStringValidator/EventHubsValidator.cs b/DiagnosticsExtension/Models/ConnectionStringValidator/EventHubsValidator.cs index 91269adc..81882c50 100644 --- a/DiagnosticsExtension/Models/ConnectionStringValidator/EventHubsValidator.cs +++ b/DiagnosticsExtension/Models/ConnectionStringValidator/EventHubsValidator.cs @@ -113,7 +113,7 @@ async public Task ValidateViaAppsettingAsync(s throw new ManagedIdentityException(String.Format(Constants.ManagedIdentityClientIdNullorEmpty, appSettingName)); } response.IdentityType = Constants.User; - client = new EventHubProducerClient(serviceUriString, eventHubName, new ManagedIdentityCredential(appSettingClientIdValue)); + client = new EventHubProducerClient(serviceUriString, eventHubName, ManagedIdentityCredentialTokenValidator.GetValidatedCredential(appSettingClientIdValue, appSettingName)); } // Creating client using System assigned managed identity else diff --git a/DiagnosticsExtension/Models/ConnectionStringValidator/ManagedIdentityCredentialTokenValidator.cs b/DiagnosticsExtension/Models/ConnectionStringValidator/ManagedIdentityCredentialTokenValidator.cs index b2ad014e..27905872 100644 --- a/DiagnosticsExtension/Models/ConnectionStringValidator/ManagedIdentityCredentialTokenValidator.cs +++ b/DiagnosticsExtension/Models/ConnectionStringValidator/ManagedIdentityCredentialTokenValidator.cs @@ -18,7 +18,7 @@ namespace DiagnosticsExtension.Models.ConnectionStringValidator { public static class ManagedIdentityCredentialTokenValidator { - public static ManagedIdentityCredential GetValidatedCredential(string clientId) + public static ManagedIdentityCredential GetValidatedCredential(string clientId, string appSettingName) { var tokenCredential = new ManagedIdentityCredential(clientId); @@ -26,11 +26,11 @@ public static ManagedIdentityCredential GetValidatedCredential(string clientId) JwtSecurityTokenHandler jwtHandler = new JwtSecurityTokenHandler(); - string appId = jwtHandler.ReadJwtToken(accessToken.Result.Token).Claims.ToList().Where(c => c.Type == "appid").FirstOrDefault().Value; + string appId = jwtHandler.ReadJwtToken(accessToken.Result.Token).Claims.First(x => x.Type == "appid").Value; - if(clientId != "" && appId != clientId) + if (appId != clientId) { - throw new ManagedIdentityException(Constants.ClientIdInvalidTokenGeneratedResponse); + throw new ManagedIdentityException(String.Format(Constants.ClientIdInvalidTokenGenerated,appSettingName)); } return tokenCredential; diff --git a/DiagnosticsExtension/Models/ConnectionStringValidator/QueueStorageValidator.cs b/DiagnosticsExtension/Models/ConnectionStringValidator/QueueStorageValidator.cs index d2273d53..539560f2 100644 --- a/DiagnosticsExtension/Models/ConnectionStringValidator/QueueStorageValidator.cs +++ b/DiagnosticsExtension/Models/ConnectionStringValidator/QueueStorageValidator.cs @@ -70,7 +70,7 @@ public async Task ValidateViaAppsettingAsync(s throw new ManagedIdentityException(String.Format(Constants.ManagedIdentityClientIdNullorEmpty, appSettingName)); } response.IdentityType = Constants.User; - client = new QueueServiceClient(serviceUri, new Azure.Identity.ManagedIdentityCredential(appSettingClientIdValue)); + client = new QueueServiceClient(serviceUri, ManagedIdentityCredentialTokenValidator.GetValidatedCredential(appSettingClientIdValue, appSettingName)); } // Creating client using System assigned managed identity else diff --git a/DiagnosticsExtension/Models/ConnectionStringValidator/ServiceBusValidator.cs b/DiagnosticsExtension/Models/ConnectionStringValidator/ServiceBusValidator.cs index 7a2dbbf2..95b67877 100644 --- a/DiagnosticsExtension/Models/ConnectionStringValidator/ServiceBusValidator.cs +++ b/DiagnosticsExtension/Models/ConnectionStringValidator/ServiceBusValidator.cs @@ -127,7 +127,7 @@ async public Task ValidateViaAppsettingAsync(s throw new ManagedIdentityException(String.Format(Constants.ManagedIdentityClientIdNullorEmpty, appSettingName)); } response.IdentityType = Constants.User; - client = new ServiceBusClient(serviceUriString, new Azure.Identity.ManagedIdentityCredential(appSettingClientIdValue)); + client = new ServiceBusClient(serviceUriString, ManagedIdentityCredentialTokenValidator.GetValidatedCredential(appSettingClientIdValue, appSettingName)); } // Creating client using System assigned managed identity else diff --git a/DiagnosticsExtension/Web.config b/DiagnosticsExtension/Web.config index 3adcc5bf..d494781f 100644 --- a/DiagnosticsExtension/Web.config +++ b/DiagnosticsExtension/Web.config @@ -106,7 +106,7 @@ - + @@ -200,6 +200,10 @@ + + + + diff --git a/DiagnosticsExtension/packages.config b/DiagnosticsExtension/packages.config index 9d8610dc..192b5261 100644 --- a/DiagnosticsExtension/packages.config +++ b/DiagnosticsExtension/packages.config @@ -43,9 +43,9 @@ - - - + + + @@ -61,7 +61,7 @@ - + From 2ec976c05783ec843678adf7bcff43dae5bdc454 Mon Sep 17 00:00:00 2001 From: Sid Krishna Date: Tue, 29 Mar 2022 03:10:38 -0700 Subject: [PATCH 12/26] Updated error messages and refactored ManagedIdentityException to support setting a summary and details. --- .../BlobStorageValidator.cs | 13 ++++++---- .../ConnectionStringValidator/Constants.cs | 24 ++++++++++++------- .../EventHubsValidator.cs | 5 ++-- ...anagedIdentityConnectionResponseUtility.cs | 6 ++--- .../Exceptions/ManagedIdentityException.cs | 11 +++++---- ...ManagedIdentityCredentialTokenValidator.cs | 3 ++- .../QueueStorageValidator.cs | 8 ++++--- .../ServiceBusValidator.cs | 5 ++-- 8 files changed, 46 insertions(+), 29 deletions(-) diff --git a/DiagnosticsExtension/Models/ConnectionStringValidator/BlobStorageValidator.cs b/DiagnosticsExtension/Models/ConnectionStringValidator/BlobStorageValidator.cs index f49e2281..dafcc4d0 100644 --- a/DiagnosticsExtension/Models/ConnectionStringValidator/BlobStorageValidator.cs +++ b/DiagnosticsExtension/Models/ConnectionStringValidator/BlobStorageValidator.cs @@ -35,6 +35,7 @@ public async Task ValidateViaAppsettingAsync(s BlobServiceClient client = null; if (envDict.Contains(appSettingName)) { + // Connection String try { string connectionString = Environment.GetEnvironmentVariable(appSettingName); @@ -51,6 +52,7 @@ public async Task ValidateViaAppsettingAsync(s } else { + // Managed Identity isManagedIdentityConnection = true; string serviceUriString = ManagedIdentityConnectionResponseUtility.ResolveManagedIdentityCommonProperty(appSettingName, ConnectionStringValidationResult.ManagedIdentityCommonProperty.blobServiceUri); if (string.IsNullOrEmpty(serviceUriString)) @@ -67,11 +69,12 @@ public async Task ValidateViaAppsettingAsync(s { if (appSettingClientCredValue != Constants.ValidCredentialValue) { - throw new ManagedIdentityException(String.Format(Constants.ManagedIdentityCredentialInvalid, appSettingName)); + throw new ManagedIdentityException(String.Format(Constants.ManagedIdentityCredentialInvalidSummary, appSettingName), Constants.ManagedIdentityCredentialInvalidDetails); } if (string.IsNullOrEmpty(appSettingClientIdValue)) { - throw new ManagedIdentityException(String.Format(Constants.ManagedIdentityClientIdNullorEmpty, appSettingName)); + throw new ManagedIdentityException(String.Format(Constants.ManagedIdentityClientIdNullOrEmptySummary, appSettingName), + String.Format(Constants.ManagedIdentityClientIdNullOrEmptyDetails, appSettingName)); } response.IdentityType = Constants.User; client = new BlobServiceClient(serviceUri, ManagedIdentityCredentialTokenValidator.GetValidatedCredential(appSettingClientIdValue,appSettingName)); @@ -88,9 +91,11 @@ public async Task ValidateViaAppsettingAsync(s string serviceuriAppSettingName = Environment.GetEnvironmentVariables().Keys.Cast().Where(k => k.StartsWith(appSettingName) && k.ToLower().EndsWith("serviceuri")).FirstOrDefault(); if (serviceuriAppSettingName == null) { - throw new ManagedIdentityException(String.Format(Constants.BlobServiceUriMissing, appSettingName)); + throw new ManagedIdentityException(Constants.BlobServiceUriMissingSummary, + Constants.BlobServiceUriMissingDetails); } - throw new ManagedIdentityException(String.Format(Constants.BlobServiceUriEmpty, serviceuriAppSettingName)); + throw new ManagedIdentityException(String.Format(Constants.BlobServiceUriEmptySummary, serviceuriAppSettingName), + Constants.BlobServiceUriEmptyDetails); } } diff --git a/DiagnosticsExtension/Models/ConnectionStringValidator/Constants.cs b/DiagnosticsExtension/Models/ConnectionStringValidator/Constants.cs index dc9449a6..dced7d16 100644 --- a/DiagnosticsExtension/Models/ConnectionStringValidator/Constants.cs +++ b/DiagnosticsExtension/Models/ConnectionStringValidator/Constants.cs @@ -23,29 +23,37 @@ public static class Constants public const string Credential = "__credential"; public const string ServiceUri = "__serviceUri"; public const string BlobServiceUri = "__blobServiceUri"; - public const string BlobServiceUriMissing = "Neither {0}__blobServiceUri nor {0}__serviceUri app settings were found. Click here to know more"; - public const string BlobServiceUriEmpty = "{0} app setting is empty. Click here to know more"; + public const string ManagedIdentityTutorial = "A relevant tutorial is also available here."; + public const string BlobServiceUriMissingSummary = "Necessary connection information was not found"; + public const string BlobServiceUriMissingDetails = "To connect to your storage account, you need to provide a connection string or use identity-based connections. To learn more please refer here. " + ManagedIdentityTutorial; + public const string BlobServiceUriEmptySummary = "The app setting {0} has an empty value."; + public const string BlobServiceUriEmptyDetails = "Refer here for relevant configuration details. " + ManagedIdentityTutorial; public const string ServiceUriEmpty = "ServiceUriEmpty"; - public const string QueueServiceUriMissing = "The {0}__queueServiceUri was not found or is set to a blank value. Click here to know more"; + public const string QueueServiceUriMissingSummary = "The app setting {0}__queueServiceUri is not configured or has an empty value."; + public const string QueueServiceUriMissingDetails = "Refer here for relevant configuration details. " + ManagedIdentityTutorial; public const string QueueServiceUri = "__queueServiceUri"; public const string ValidCredentialValue = "managedidentity"; public const string FullyQualifiedNamespace = "__fullyQualifiedNamespace"; - public const string ManagedIdentityClientIdNullorEmpty = "The {0}__clientId was not found or is set to a blank value. Click here to know more"; + public const string ManagedIdentityClientIdNullOrEmptySummary = "The app setting {0}__clientId was expected but not found."; + public const string ManagedIdentityClientIdNullOrEmptyDetails = "When the app setting {0}__credential is configured to \"managedidentity\", the clientId of a user assigned managed identity assigned to the Function App is expected in the app setting {0}__clientId. Refer here for details. " + ManagedIdentityTutorial; public const string AuthorizationFailure = "Authorization failure"; public const string AuthenticationFailure = "Authentication failure"; public const string ConnectionInformation = "Necessary connection information was not found"; public const string InvalidConnection = "Invalid connection string"; public const string ResourceNotFound = "Resource not found"; public const string DetailsHeader = "Please see exception below. "; - public const string ClientIdInvalidTokenGenerated = "An invalid clientId has been provided in {0}__clientId. But managed identity connection was attempted because function app has system assigned identity turned on. "; - public const string SystemAssignedAuthFailure = "The azure resource mentioned in {0} is not provided with access to the function app using system assigned identity. Click here to know more"; - public const string UserAssignedAuthFailure = "The azure resource mentioned in {0} is not provided with access to the managed identity resource having clientId specified in appsetting {1}__clientId . Click here to know more"; + public const string ClientIdInvalidTokenGeneratedSummary = "The ClientId configured in the app setting {0}__clientId does not match any user assigned managed identity assigned to this app."; + public const string ClientIdInvalidTokenGeneratedDetails = "Refer here for details related to configuring connections via managed identity. " + ManagedIdentityTutorial; + public const string SystemAssignedAuthFailure = "The system assigned managed identity for this Function App does not have access to the resource configured in {0}. Refer here for details around configuring connections via managed identity. " + ManagedIdentityTutorial; + public const string UserAssignedAuthFailure = "The configured user assigned managed identity does not have access to the resource configured in {0}. Refer here for details around configuring connections via managed identity. " + ManagedIdentityTutorial; + public const string AuthFailureDetails = "Authentication failure -the credentials in the configured connection string are either invalid or expired. Please update the app setting with a valid connection string."; public const string DnsLookupFailedDetails = "The service resource specified in the connection string was not found. Please check the value of the setting."; public const string FQNamespaceResourceNotFound = "The resource specified in the app setting {0}__fullyQualifiedNamespace was not found. Please check the value of the setting."; public const string StorageAccountResourceNotFound = "The resource specified in the app setting {0} was not found. Please check the value of the setting."; public const string MalformedConnectionStringDetails = "The connection string configured is invalid(e.g.missing some required elements). Please check the value configured in the app setting "; - public const string ManagedIdentityCredentialInvalid = "The {0}__credential was not set to 'managedidentity'. Click here to know more"; + public const string ManagedIdentityCredentialInvalidSummary = "The app setting {0}__credential is defined but not valid. To configure user assigned managed identity, set it's value to \"managedidentity\"."; + public const string ManagedIdentityCredentialInvalidDetails = "Refer here for more information about configuring this app setting. " + ManagedIdentityTutorial; #endregion } } diff --git a/DiagnosticsExtension/Models/ConnectionStringValidator/EventHubsValidator.cs b/DiagnosticsExtension/Models/ConnectionStringValidator/EventHubsValidator.cs index 81882c50..080ac101 100644 --- a/DiagnosticsExtension/Models/ConnectionStringValidator/EventHubsValidator.cs +++ b/DiagnosticsExtension/Models/ConnectionStringValidator/EventHubsValidator.cs @@ -106,11 +106,12 @@ async public Task ValidateViaAppsettingAsync(s { if (appSettingClientCredValue != Constants.ValidCredentialValue) { - throw new ManagedIdentityException(String.Format(Constants.ManagedIdentityCredentialInvalid, appSettingName)); + throw new ManagedIdentityException(String.Format(Constants.ManagedIdentityCredentialInvalidSummary, appSettingName), Constants.ManagedIdentityCredentialInvalidDetails); } if (string.IsNullOrEmpty(appSettingClientIdValue)) { - throw new ManagedIdentityException(String.Format(Constants.ManagedIdentityClientIdNullorEmpty, appSettingName)); + throw new ManagedIdentityException(String.Format(Constants.ManagedIdentityClientIdNullOrEmptySummary, appSettingName), + String.Format(Constants.ManagedIdentityClientIdNullOrEmptyDetails, appSettingName)); } response.IdentityType = Constants.User; client = new EventHubProducerClient(serviceUriString, eventHubName, ManagedIdentityCredentialTokenValidator.GetValidatedCredential(appSettingClientIdValue, appSettingName)); diff --git a/DiagnosticsExtension/Models/ConnectionStringValidator/Exceptions/ManagedIdentityConnectionResponseUtility.cs b/DiagnosticsExtension/Models/ConnectionStringValidator/Exceptions/ManagedIdentityConnectionResponseUtility.cs index e08cee10..abd2b7a4 100644 --- a/DiagnosticsExtension/Models/ConnectionStringValidator/Exceptions/ManagedIdentityConnectionResponseUtility.cs +++ b/DiagnosticsExtension/Models/ConnectionStringValidator/Exceptions/ManagedIdentityConnectionResponseUtility.cs @@ -36,7 +36,7 @@ public static void EvaluateResponseStatus(Exception e, ConnectionStringType type } else { - response.StatusDetails = String.Format(Constants.UserAssignedAuthFailure, GetTargetConnectionAppSettingName(type, appSettingName), appSettingName); + response.StatusDetails = String.Format(Constants.UserAssignedAuthFailure, GetTargetConnectionAppSettingName(type, appSettingName)); } response.Exception = e; @@ -58,9 +58,7 @@ public static void EvaluateResponseStatus(Exception e, ConnectionStringType type { response.Status = ConnectionStringValidationResult.ResultStatus.DnsLookupFailed; - response.StatusSummary = Constants.ResourceNotFound; - response.StatusDetails = String.Format(Constants.StorageAccountResourceNotFound, GetTargetConnectionAppSettingName(type, appSettingName)); - response.Exception = e; + response.StatusSummary = String.Format(Constants.StorageAccountResourceNotFound, GetTargetConnectionAppSettingName(type, appSettingName)); } else if (e.Message.Contains("No such host is known")) // event hub and service bus { diff --git a/DiagnosticsExtension/Models/ConnectionStringValidator/Exceptions/ManagedIdentityException.cs b/DiagnosticsExtension/Models/ConnectionStringValidator/Exceptions/ManagedIdentityException.cs index f905d8d9..0dd6e0c9 100644 --- a/DiagnosticsExtension/Models/ConnectionStringValidator/Exceptions/ManagedIdentityException.cs +++ b/DiagnosticsExtension/Models/ConnectionStringValidator/Exceptions/ManagedIdentityException.cs @@ -14,16 +14,17 @@ namespace DiagnosticsExtension.Models.ConnectionStringValidator.Exceptions { public class ManagedIdentityException : Exception { - public ManagedIdentityException() : base() - { - } + public string MessageSummary { get; } + public string MessageDetails { get; } - public ManagedIdentityException(string message) : base(message) + public ManagedIdentityException() : base() { } - public ManagedIdentityException(string message, Exception innerException) : base(message, innerException) + public ManagedIdentityException(string summary, string details) : base() { + this.MessageSummary = summary; + this.MessageDetails = details; } } } diff --git a/DiagnosticsExtension/Models/ConnectionStringValidator/ManagedIdentityCredentialTokenValidator.cs b/DiagnosticsExtension/Models/ConnectionStringValidator/ManagedIdentityCredentialTokenValidator.cs index 27905872..32f0c749 100644 --- a/DiagnosticsExtension/Models/ConnectionStringValidator/ManagedIdentityCredentialTokenValidator.cs +++ b/DiagnosticsExtension/Models/ConnectionStringValidator/ManagedIdentityCredentialTokenValidator.cs @@ -30,7 +30,8 @@ public static ManagedIdentityCredential GetValidatedCredential(string clientId, if (appId != clientId) { - throw new ManagedIdentityException(String.Format(Constants.ClientIdInvalidTokenGenerated,appSettingName)); + throw new ManagedIdentityException(String.Format(Constants.ClientIdInvalidTokenGeneratedSummary,appSettingName), + Constants.ClientIdInvalidTokenGeneratedDetails); } return tokenCredential; diff --git a/DiagnosticsExtension/Models/ConnectionStringValidator/QueueStorageValidator.cs b/DiagnosticsExtension/Models/ConnectionStringValidator/QueueStorageValidator.cs index 539560f2..95e959c5 100644 --- a/DiagnosticsExtension/Models/ConnectionStringValidator/QueueStorageValidator.cs +++ b/DiagnosticsExtension/Models/ConnectionStringValidator/QueueStorageValidator.cs @@ -63,11 +63,12 @@ public async Task ValidateViaAppsettingAsync(s { if (appSettingClientCredValue != Constants.ValidCredentialValue) { - throw new ManagedIdentityException(String.Format(Constants.ManagedIdentityCredentialInvalid, appSettingName)); + throw new ManagedIdentityException(String.Format(Constants.ManagedIdentityCredentialInvalidSummary, appSettingName), Constants.ManagedIdentityCredentialInvalidDetails); } if (string.IsNullOrEmpty(appSettingClientIdValue)) { - throw new ManagedIdentityException(String.Format(Constants.ManagedIdentityClientIdNullorEmpty, appSettingName)); + throw new ManagedIdentityException(String.Format(Constants.ManagedIdentityClientIdNullOrEmptySummary, appSettingName), + String.Format(Constants.ManagedIdentityClientIdNullOrEmptyDetails, appSettingName)); } response.IdentityType = Constants.User; client = new QueueServiceClient(serviceUri, ManagedIdentityCredentialTokenValidator.GetValidatedCredential(appSettingClientIdValue, appSettingName)); @@ -81,7 +82,8 @@ public async Task ValidateViaAppsettingAsync(s } else { - throw new ManagedIdentityException(String.Format(Constants.QueueServiceUriMissing, appSettingName)); + throw new ManagedIdentityException(String.Format(Constants.QueueServiceUriMissingSummary, appSettingName), + Constants.QueueServiceUriMissingDetails); } } var resultSegment = diff --git a/DiagnosticsExtension/Models/ConnectionStringValidator/ServiceBusValidator.cs b/DiagnosticsExtension/Models/ConnectionStringValidator/ServiceBusValidator.cs index 95b67877..34adb16a 100644 --- a/DiagnosticsExtension/Models/ConnectionStringValidator/ServiceBusValidator.cs +++ b/DiagnosticsExtension/Models/ConnectionStringValidator/ServiceBusValidator.cs @@ -120,11 +120,12 @@ async public Task ValidateViaAppsettingAsync(s { if (appSettingClientCredValue != Constants.ValidCredentialValue) { - throw new ManagedIdentityException(String.Format(Constants.ManagedIdentityCredentialInvalid, appSettingName)); + throw new ManagedIdentityException(String.Format(Constants.ManagedIdentityCredentialInvalidSummary, appSettingName), Constants.ManagedIdentityCredentialInvalidDetails); } if (string.IsNullOrEmpty(appSettingClientIdValue)) { - throw new ManagedIdentityException(String.Format(Constants.ManagedIdentityClientIdNullorEmpty, appSettingName)); + throw new ManagedIdentityException(String.Format(Constants.ManagedIdentityClientIdNullOrEmptySummary, appSettingName), + String.Format(Constants.ManagedIdentityClientIdNullOrEmptyDetails, appSettingName)); } response.IdentityType = Constants.User; client = new ServiceBusClient(serviceUriString, ManagedIdentityCredentialTokenValidator.GetValidatedCredential(appSettingClientIdValue, appSettingName)); From 7a375a309b168499041247b7e988d85e40648efd Mon Sep 17 00:00:00 2001 From: Sid Krishna Date: Tue, 29 Mar 2022 09:32:07 -0700 Subject: [PATCH 13/26] Additional changes for error messages --- .../Models/ConnectionStringValidator/Constants.cs | 12 ++++-------- .../ManagedIdentityConnectionResponseUtility.cs | 4 ++-- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/DiagnosticsExtension/Models/ConnectionStringValidator/Constants.cs b/DiagnosticsExtension/Models/ConnectionStringValidator/Constants.cs index dced7d16..6319a66f 100644 --- a/DiagnosticsExtension/Models/ConnectionStringValidator/Constants.cs +++ b/DiagnosticsExtension/Models/ConnectionStringValidator/Constants.cs @@ -21,8 +21,6 @@ public static class Constants public const string ColonSeparator = ":"; public const string ClientId = "__clientId"; public const string Credential = "__credential"; - public const string ServiceUri = "__serviceUri"; - public const string BlobServiceUri = "__blobServiceUri"; public const string ManagedIdentityTutorial = "A relevant tutorial is also available here."; public const string BlobServiceUriMissingSummary = "Necessary connection information was not found"; public const string BlobServiceUriMissingDetails = "To connect to your storage account, you need to provide a connection string or use identity-based connections. To learn more please refer here. " + ManagedIdentityTutorial; @@ -34,15 +32,13 @@ public static class Constants public const string QueueServiceUri = "__queueServiceUri"; public const string ValidCredentialValue = "managedidentity"; public const string FullyQualifiedNamespace = "__fullyQualifiedNamespace"; - public const string ManagedIdentityClientIdNullOrEmptySummary = "The app setting {0}__clientId was expected but not found."; - public const string ManagedIdentityClientIdNullOrEmptyDetails = "When the app setting {0}__credential is configured to \"managedidentity\", the clientId of a user assigned managed identity assigned to the Function App is expected in the app setting {0}__clientId. Refer here for details. " + ManagedIdentityTutorial; + public const string ManagedIdentityClientIdNullOrEmptySummary = "The app setting {0}" + ClientId + " was expected but not found."; + public const string ManagedIdentityClientIdNullOrEmptyDetails = "When the app setting {0}" + Credential + " is configured to \"managedidentity\", the clientId of a user assigned managed identity assigned to the Function App is expected in the app setting {0}" + ClientId + ". Refer here for details. " + ManagedIdentityTutorial; public const string AuthorizationFailure = "Authorization failure"; public const string AuthenticationFailure = "Authentication failure"; - public const string ConnectionInformation = "Necessary connection information was not found"; public const string InvalidConnection = "Invalid connection string"; public const string ResourceNotFound = "Resource not found"; - public const string DetailsHeader = "Please see exception below. "; - public const string ClientIdInvalidTokenGeneratedSummary = "The ClientId configured in the app setting {0}__clientId does not match any user assigned managed identity assigned to this app."; + public const string ClientIdInvalidTokenGeneratedSummary = "The ClientId configured in the app setting {0}" + ClientId + " does not match any user assigned managed identity assigned to this app."; public const string ClientIdInvalidTokenGeneratedDetails = "Refer here for details related to configuring connections via managed identity. " + ManagedIdentityTutorial; public const string SystemAssignedAuthFailure = "The system assigned managed identity for this Function App does not have access to the resource configured in {0}. Refer here for details around configuring connections via managed identity. " + ManagedIdentityTutorial; public const string UserAssignedAuthFailure = "The configured user assigned managed identity does not have access to the resource configured in {0}. Refer here for details around configuring connections via managed identity. " + ManagedIdentityTutorial; @@ -52,7 +48,7 @@ public static class Constants public const string FQNamespaceResourceNotFound = "The resource specified in the app setting {0}__fullyQualifiedNamespace was not found. Please check the value of the setting."; public const string StorageAccountResourceNotFound = "The resource specified in the app setting {0} was not found. Please check the value of the setting."; public const string MalformedConnectionStringDetails = "The connection string configured is invalid(e.g.missing some required elements). Please check the value configured in the app setting "; - public const string ManagedIdentityCredentialInvalidSummary = "The app setting {0}__credential is defined but not valid. To configure user assigned managed identity, set it's value to \"managedidentity\"."; + public const string ManagedIdentityCredentialInvalidSummary = "The app setting {0}" + Credential + " is defined but not valid. To configure user assigned managed identity, set it's value to \"managedidentity\"."; public const string ManagedIdentityCredentialInvalidDetails = "Refer here for more information about configuring this app setting. " + ManagedIdentityTutorial; #endregion } diff --git a/DiagnosticsExtension/Models/ConnectionStringValidator/Exceptions/ManagedIdentityConnectionResponseUtility.cs b/DiagnosticsExtension/Models/ConnectionStringValidator/Exceptions/ManagedIdentityConnectionResponseUtility.cs index abd2b7a4..1075725d 100644 --- a/DiagnosticsExtension/Models/ConnectionStringValidator/Exceptions/ManagedIdentityConnectionResponseUtility.cs +++ b/DiagnosticsExtension/Models/ConnectionStringValidator/Exceptions/ManagedIdentityConnectionResponseUtility.cs @@ -22,8 +22,8 @@ public static void EvaluateResponseStatus(Exception e, ConnectionStringType type if (e is ManagedIdentityException) { response.Status = ConnectionStringValidationResult.ResultStatus.ManagedIdentityConnectionFailed; - response.StatusSummary = Constants.ConnectionInformation; - response.StatusDetails = Constants.DetailsHeader; + response.StatusSummary = ((ManagedIdentityException)e).MessageSummary; + response.StatusDetails = ((ManagedIdentityException)e).MessageDetails; response.Exception = e; } else if (e is UnauthorizedAccessException && e.Message.Contains("unauthorized") || e.Message.Contains("Unauthorized") || e.Message.Contains("request is not authorized")) From e397ada98138c9c096f952973d9f1173900a6f14 Mon Sep 17 00:00:00 2001 From: Sid Krishna Date: Tue, 29 Mar 2022 10:57:40 -0700 Subject: [PATCH 14/26] Additional error msg and logic changes --- .../BlobStorageValidator.cs | 23 ++++++++++--------- .../ConnectionStringValidator/Constants.cs | 4 ++-- ...anagedIdentityConnectionResponseUtility.cs | 4 ++-- 3 files changed, 16 insertions(+), 15 deletions(-) diff --git a/DiagnosticsExtension/Models/ConnectionStringValidator/BlobStorageValidator.cs b/DiagnosticsExtension/Models/ConnectionStringValidator/BlobStorageValidator.cs index dafcc4d0..6c6dfd3f 100644 --- a/DiagnosticsExtension/Models/ConnectionStringValidator/BlobStorageValidator.cs +++ b/DiagnosticsExtension/Models/ConnectionStringValidator/BlobStorageValidator.cs @@ -61,27 +61,28 @@ public async Task ValidateViaAppsettingAsync(s } if (!string.IsNullOrEmpty(serviceUriString)) { + string clientIdAppSettingKey = Environment.GetEnvironmentVariables().Keys.Cast().Where(k => k.StartsWith(appSettingName) && k.ToLower().EndsWith("clientId")).FirstOrDefault(); appSettingClientIdValue = ManagedIdentityConnectionResponseUtility.ResolveManagedIdentityCommonProperty(appSettingName, ConnectionStringValidationResult.ManagedIdentityCommonProperty.clientId); appSettingClientCredValue = ManagedIdentityConnectionResponseUtility.ResolveManagedIdentityCommonProperty(appSettingName, ConnectionStringValidationResult.ManagedIdentityCommonProperty.credential); - Uri serviceUri = new Uri(serviceUriString); - // Creating client using User assigned managed identity - if (appSettingClientCredValue != null) + if (appSettingClientCredValue != null && appSettingClientCredValue != Constants.ValidCredentialValue) { - if (appSettingClientCredValue != Constants.ValidCredentialValue) - { - throw new ManagedIdentityException(String.Format(Constants.ManagedIdentityCredentialInvalidSummary, appSettingName), Constants.ManagedIdentityCredentialInvalidDetails); - } - if (string.IsNullOrEmpty(appSettingClientIdValue)) + throw new ManagedIdentityException(String.Format(Constants.ManagedIdentityCredentialInvalidSummary, appSettingName), Constants.ManagedIdentityCredentialInvalidDetails); + } + Uri serviceUri = new Uri(serviceUriString); + // If the user has configured __credential with "managedidentity" and set an app setting for __clientId (even if its empty) we assume their intent is to use a user assigned managed identity + if (appSettingClientCredValue != null && clientIdAppSettingKey != null) + { + if (appSettingClientIdValue == null) { - throw new ManagedIdentityException(String.Format(Constants.ManagedIdentityClientIdNullOrEmptySummary, appSettingName), - String.Format(Constants.ManagedIdentityClientIdNullOrEmptyDetails, appSettingName)); + throw new ManagedIdentityException(String.Format(Constants.ManagedIdentityClientIdEmptySummary, appSettingName), + String.Format(Constants.ManagedIdentityClientIdEmptyDetails, appSettingName)); } response.IdentityType = Constants.User; client = new BlobServiceClient(serviceUri, ManagedIdentityCredentialTokenValidator.GetValidatedCredential(appSettingClientIdValue,appSettingName)); } - // Creating client using System assigned managed identity else { + // Creating client using System assigned managed identity response.IdentityType = Constants.System; client = new BlobServiceClient(serviceUri, new Azure.Identity.ManagedIdentityCredential()); } diff --git a/DiagnosticsExtension/Models/ConnectionStringValidator/Constants.cs b/DiagnosticsExtension/Models/ConnectionStringValidator/Constants.cs index 6319a66f..0a6ab3f4 100644 --- a/DiagnosticsExtension/Models/ConnectionStringValidator/Constants.cs +++ b/DiagnosticsExtension/Models/ConnectionStringValidator/Constants.cs @@ -45,10 +45,10 @@ public static class Constants public const string AuthFailureDetails = "Authentication failure -the credentials in the configured connection string are either invalid or expired. Please update the app setting with a valid connection string."; public const string DnsLookupFailedDetails = "The service resource specified in the connection string was not found. Please check the value of the setting."; - public const string FQNamespaceResourceNotFound = "The resource specified in the app setting {0}__fullyQualifiedNamespace was not found. Please check the value of the setting."; + public const string FQNamespaceResourceNotFound = "The resource specified in the app setting {0}" + FullyQualifiedNamespace + " was not found. Please check the value of the setting."; public const string StorageAccountResourceNotFound = "The resource specified in the app setting {0} was not found. Please check the value of the setting."; public const string MalformedConnectionStringDetails = "The connection string configured is invalid(e.g.missing some required elements). Please check the value configured in the app setting "; - public const string ManagedIdentityCredentialInvalidSummary = "The app setting {0}" + Credential + " is defined but not valid. To configure user assigned managed identity, set it's value to \"managedidentity\"."; + public const string ManagedIdentityCredentialInvalidSummary = "The app setting {0}" + Credential + " is defined but not valid. To use identity based connections, set it's value to \"managedidentity\"."; public const string ManagedIdentityCredentialInvalidDetails = "Refer here for more information about configuring this app setting. " + ManagedIdentityTutorial; #endregion } diff --git a/DiagnosticsExtension/Models/ConnectionStringValidator/Exceptions/ManagedIdentityConnectionResponseUtility.cs b/DiagnosticsExtension/Models/ConnectionStringValidator/Exceptions/ManagedIdentityConnectionResponseUtility.cs index 1075725d..7b65e55b 100644 --- a/DiagnosticsExtension/Models/ConnectionStringValidator/Exceptions/ManagedIdentityConnectionResponseUtility.cs +++ b/DiagnosticsExtension/Models/ConnectionStringValidator/Exceptions/ManagedIdentityConnectionResponseUtility.cs @@ -44,13 +44,13 @@ public static void EvaluateResponseStatus(Exception e, ConnectionStringType type else if (e is AuthenticationFailedException && e.Message.Contains("ManagedIdentityCredential")) { response.Status = ConnectionStringValidationResult.ResultStatus.ManagedIdentityNotConfigured; - response.StatusSummary = "Your app is not having managed identity configured for making a successful connection. Click here to know more"; + response.StatusSummary = "Your app is configured to use identity based connection but does not have a system assigned managed identity assigned. Refer here for details."; response.Exception = e; } else if (e.Message.Contains("fullyQualifiedNamespace")) { response.Status = ConnectionStringValidationResult.ResultStatus.FullyQualifiedNamespaceMissing; - response.StatusSummary = "The app setting " + appSettingName + "__fullyQualifiedNamespace was not found or is set to a blank value Click here to know more"; + response.StatusSummary = "The app setting " + appSettingName + FullyQualifiedNamespace + " was not found or is set to a blank value. Refer here for details."; response.Exception = e; } else if (e.InnerException != null && From d01dd316284cac5169bbde491319ba1068df1dd0 Mon Sep 17 00:00:00 2001 From: Gajibilli Koteswara Rao Date: Fri, 1 Apr 2022 21:16:22 +0530 Subject: [PATCH 15/26] Code changes as per the latest comments --- .../BlobStorageValidator.cs | 8 +-- .../ConnectionStringValidator/Constants.cs | 18 +++++-- .../EventHubsValidator.cs | 51 ++++++++++++++----- .../ConnectionStringResponseUtility.cs | 11 +++- ...anagedIdentityConnectionResponseUtility.cs | 10 ++-- .../QueueStorageValidator.cs | 27 ++++++---- .../ServiceBusValidator.cs | 50 +++++++++++++----- 7 files changed, 126 insertions(+), 49 deletions(-) diff --git a/DiagnosticsExtension/Models/ConnectionStringValidator/BlobStorageValidator.cs b/DiagnosticsExtension/Models/ConnectionStringValidator/BlobStorageValidator.cs index 6c6dfd3f..33e9d58e 100644 --- a/DiagnosticsExtension/Models/ConnectionStringValidator/BlobStorageValidator.cs +++ b/DiagnosticsExtension/Models/ConnectionStringValidator/BlobStorageValidator.cs @@ -61,7 +61,7 @@ public async Task ValidateViaAppsettingAsync(s } if (!string.IsNullOrEmpty(serviceUriString)) { - string clientIdAppSettingKey = Environment.GetEnvironmentVariables().Keys.Cast().Where(k => k.StartsWith(appSettingName) && k.ToLower().EndsWith("clientId")).FirstOrDefault(); + string clientIdAppSettingKey = Environment.GetEnvironmentVariables().Keys.Cast().Where(k => k.StartsWith(appSettingName) && k.ToLower().EndsWith("clientid")).FirstOrDefault(); appSettingClientIdValue = ManagedIdentityConnectionResponseUtility.ResolveManagedIdentityCommonProperty(appSettingName, ConnectionStringValidationResult.ManagedIdentityCommonProperty.clientId); appSettingClientCredValue = ManagedIdentityConnectionResponseUtility.ResolveManagedIdentityCommonProperty(appSettingName, ConnectionStringValidationResult.ManagedIdentityCommonProperty.credential); if (appSettingClientCredValue != null && appSettingClientCredValue != Constants.ValidCredentialValue) @@ -72,7 +72,7 @@ public async Task ValidateViaAppsettingAsync(s // If the user has configured __credential with "managedidentity" and set an app setting for __clientId (even if its empty) we assume their intent is to use a user assigned managed identity if (appSettingClientCredValue != null && clientIdAppSettingKey != null) { - if (appSettingClientIdValue == null) + if (string.IsNullOrEmpty(appSettingClientIdValue)) { throw new ManagedIdentityException(String.Format(Constants.ManagedIdentityClientIdEmptySummary, appSettingName), String.Format(Constants.ManagedIdentityClientIdEmptyDetails, appSettingName)); @@ -92,11 +92,11 @@ public async Task ValidateViaAppsettingAsync(s string serviceuriAppSettingName = Environment.GetEnvironmentVariables().Keys.Cast().Where(k => k.StartsWith(appSettingName) && k.ToLower().EndsWith("serviceuri")).FirstOrDefault(); if (serviceuriAppSettingName == null) { - throw new ManagedIdentityException(Constants.BlobServiceUriMissingSummary, + throw new ManagedIdentityException(Constants.ConnectionInfoMissingSummary, Constants.BlobServiceUriMissingDetails); } throw new ManagedIdentityException(String.Format(Constants.BlobServiceUriEmptySummary, serviceuriAppSettingName), - Constants.BlobServiceUriEmptyDetails); + Constants.ServiceUriEmptyDetails); } } diff --git a/DiagnosticsExtension/Models/ConnectionStringValidator/Constants.cs b/DiagnosticsExtension/Models/ConnectionStringValidator/Constants.cs index 0a6ab3f4..af572749 100644 --- a/DiagnosticsExtension/Models/ConnectionStringValidator/Constants.cs +++ b/DiagnosticsExtension/Models/ConnectionStringValidator/Constants.cs @@ -22,18 +22,28 @@ public static class Constants public const string ClientId = "__clientId"; public const string Credential = "__credential"; public const string ManagedIdentityTutorial = "A relevant tutorial is also available here."; - public const string BlobServiceUriMissingSummary = "Necessary connection information was not found"; + public const string ConnectionInfoMissingSummary = "Necessary connection information was not found"; public const string BlobServiceUriMissingDetails = "To connect to your storage account, you need to provide a connection string or use identity-based connections. To learn more please refer here. " + ManagedIdentityTutorial; + public const string ServiceBusFQMissingDetails = "To connect to your service bus, you need to provide a connection string or use identity-based connections. To learn more please refer here. " + ManagedIdentityTutorial; + public const string EventHubFQMissingDetails = "To connect to your event hub, you need to provide a connection string or use identity-based connections. To learn more please refer here. " + ManagedIdentityTutorial; + public const string FullyQualifiedNamespaceEmptySummary = "The app setting {0} has an empty value."; public const string BlobServiceUriEmptySummary = "The app setting {0} has an empty value."; - public const string BlobServiceUriEmptyDetails = "Refer here for relevant configuration details. " + ManagedIdentityTutorial; + public const string QueueServiceUriEmptySummary = "The app setting {0}__queueServiceUri has an empty value."; + public const string ServiceUriEmptyDetails = "Refer here for relevant configuration details. " + ManagedIdentityTutorial; + public const string ServiceBusFQNSEmptyDetails = "Refer here for relevant configuration details. " + ManagedIdentityTutorial; + public const string EventHubFQNSEmptyDetails = "Refer here for relevant configuration details. " + ManagedIdentityTutorial; + public const string ServiceUriEmpty = "ServiceUriEmpty"; public const string QueueServiceUriMissingSummary = "The app setting {0}__queueServiceUri is not configured or has an empty value."; - public const string QueueServiceUriMissingDetails = "Refer here for relevant configuration details. " + ManagedIdentityTutorial; + public const string QueueServiceUriMissingDetails = "To connect to your storage account, you need to provide a connection string or use identity-based connections. To learn more please refer here. " + ManagedIdentityTutorial; public const string QueueServiceUri = "__queueServiceUri"; public const string ValidCredentialValue = "managedidentity"; public const string FullyQualifiedNamespace = "__fullyQualifiedNamespace"; public const string ManagedIdentityClientIdNullOrEmptySummary = "The app setting {0}" + ClientId + " was expected but not found."; public const string ManagedIdentityClientIdNullOrEmptyDetails = "When the app setting {0}" + Credential + " is configured to \"managedidentity\", the clientId of a user assigned managed identity assigned to the Function App is expected in the app setting {0}" + ClientId + ". Refer here for details. " + ManagedIdentityTutorial; + public const string ManagedIdentityClientIdEmptySummary = "The app setting {0}" + ClientId + " has an empty value."; + public const string ManagedIdentityClientIdEmptyDetails = "When the app setting {0}" + Credential + " is configured to \"managedidentity\", the clientId of a user assigned managed identity assigned to the Function App is expected in the app setting {0}" + ClientId + ". Refer here for details. " + ManagedIdentityTutorial; + public const string AuthorizationFailure = "Authorization failure"; public const string AuthenticationFailure = "Authentication failure"; public const string InvalidConnection = "Invalid connection string"; @@ -43,7 +53,7 @@ public static class Constants public const string SystemAssignedAuthFailure = "The system assigned managed identity for this Function App does not have access to the resource configured in {0}. Refer here for details around configuring connections via managed identity. " + ManagedIdentityTutorial; public const string UserAssignedAuthFailure = "The configured user assigned managed identity does not have access to the resource configured in {0}. Refer here for details around configuring connections via managed identity. " + ManagedIdentityTutorial; - public const string AuthFailureDetails = "Authentication failure -the credentials in the configured connection string are either invalid or expired. Please update the app setting with a valid connection string."; + public const string AuthFailureDetails = "Authentication failure - the credentials in the configured connection string are either invalid or expired. Please update the app setting with a valid connection string."; public const string DnsLookupFailedDetails = "The service resource specified in the connection string was not found. Please check the value of the setting."; public const string FQNamespaceResourceNotFound = "The resource specified in the app setting {0}" + FullyQualifiedNamespace + " was not found. Please check the value of the setting."; public const string StorageAccountResourceNotFound = "The resource specified in the app setting {0} was not found. Please check the value of the setting."; diff --git a/DiagnosticsExtension/Models/ConnectionStringValidator/EventHubsValidator.cs b/DiagnosticsExtension/Models/ConnectionStringValidator/EventHubsValidator.cs index 080ac101..cc294236 100644 --- a/DiagnosticsExtension/Models/ConnectionStringValidator/EventHubsValidator.cs +++ b/DiagnosticsExtension/Models/ConnectionStringValidator/EventHubsValidator.cs @@ -12,6 +12,7 @@ using System.Threading.Tasks; using Azure.Identity; using Azure.Messaging.EventHubs.Producer; +using System.Linq; namespace DiagnosticsExtension.Models.ConnectionStringValidator { @@ -87,9 +88,17 @@ async public Task ValidateViaAppsettingAsync(s try { string connectionString = Environment.GetEnvironmentVariable(appSettingName); + if (string.IsNullOrEmpty(connectionString)) + { + throw new EmptyConnectionStringException(); + } connectionString += ";EntityPath=" + eventHubName; client = new EventHubProducerClient(connectionString); } + catch (EmptyConnectionStringException e) + { + throw new EmptyConnectionStringException(e.Message, e); + } catch (Exception e) { throw new MalformedConnectionStringException(e.Message, e); @@ -99,28 +108,44 @@ async public Task ValidateViaAppsettingAsync(s { isManagedIdentityConnection = true; string serviceUriString = ManagedIdentityConnectionResponseUtility.ResolveManagedIdentityCommonProperty(appSettingName, ConnectionStringValidationResult.ManagedIdentityCommonProperty.fullyQualifiedNamespace); - appSettingClientIdValue = ManagedIdentityConnectionResponseUtility.ResolveManagedIdentityCommonProperty(appSettingName, ConnectionStringValidationResult.ManagedIdentityCommonProperty.clientId); - appSettingClientCredValue = ManagedIdentityConnectionResponseUtility.ResolveManagedIdentityCommonProperty(appSettingName, ConnectionStringValidationResult.ManagedIdentityCommonProperty.credential); - // Creating client using User assigned managed identity - if (appSettingClientCredValue != null) + if (!string.IsNullOrEmpty(serviceUriString)) { - if (appSettingClientCredValue != Constants.ValidCredentialValue) + string clientIdAppSettingKey = Environment.GetEnvironmentVariables().Keys.Cast().Where(k => k.StartsWith(appSettingName) && k.ToLower().EndsWith("clientid")).FirstOrDefault(); + appSettingClientIdValue = ManagedIdentityConnectionResponseUtility.ResolveManagedIdentityCommonProperty(appSettingName, ConnectionStringValidationResult.ManagedIdentityCommonProperty.clientId); + appSettingClientCredValue = ManagedIdentityConnectionResponseUtility.ResolveManagedIdentityCommonProperty(appSettingName, ConnectionStringValidationResult.ManagedIdentityCommonProperty.credential); + if (appSettingClientCredValue != null && appSettingClientCredValue != Constants.ValidCredentialValue) { throw new ManagedIdentityException(String.Format(Constants.ManagedIdentityCredentialInvalidSummary, appSettingName), Constants.ManagedIdentityCredentialInvalidDetails); } - if (string.IsNullOrEmpty(appSettingClientIdValue)) + // If the user has configured __credential with "managedidentity" and set an app setting for __clientId (even if its empty) we assume their intent is to use a user assigned managed identity + if (appSettingClientCredValue != null && clientIdAppSettingKey != null) { - throw new ManagedIdentityException(String.Format(Constants.ManagedIdentityClientIdNullOrEmptySummary, appSettingName), - String.Format(Constants.ManagedIdentityClientIdNullOrEmptyDetails, appSettingName)); + if (string.IsNullOrEmpty(appSettingClientIdValue)) + { + throw new ManagedIdentityException(String.Format(Constants.ManagedIdentityClientIdEmptySummary, appSettingName), + String.Format(Constants.ManagedIdentityClientIdEmptyDetails, appSettingName)); + } + response.IdentityType = Constants.User; + client = new EventHubProducerClient(serviceUriString, eventHubName, ManagedIdentityCredentialTokenValidator.GetValidatedCredential(appSettingClientIdValue, appSettingName)); + } + // Creating client using System assigned managed identity + else + { + response.IdentityType = Constants.System; + client = new EventHubProducerClient(serviceUriString, eventHubName, new ManagedIdentityCredential()); } - response.IdentityType = Constants.User; - client = new EventHubProducerClient(serviceUriString, eventHubName, ManagedIdentityCredentialTokenValidator.GetValidatedCredential(appSettingClientIdValue, appSettingName)); } - // Creating client using System assigned managed identity else { - response.IdentityType = Constants.System; - client = new EventHubProducerClient(serviceUriString, eventHubName, new ManagedIdentityCredential()); + string fullyQualifiedNamespaceAppSettingName = Environment.GetEnvironmentVariables().Keys.Cast().Where(k => k.StartsWith(appSettingName) && k.ToLower().EndsWith("fullyqualifiednamespace")).FirstOrDefault(); + if (fullyQualifiedNamespaceAppSettingName == null) + { + throw new ManagedIdentityException(Constants.ConnectionInfoMissingSummary, + Constants.EventHubFQMissingDetails); + } + throw new ManagedIdentityException(String.Format(Constants.FullyQualifiedNamespaceEmptySummary, fullyQualifiedNamespaceAppSettingName), + Constants.EventHubFQNSEmptyDetails); + } } await client.GetPartitionIdsAsync(); diff --git a/DiagnosticsExtension/Models/ConnectionStringValidator/Exceptions/ConnectionStringResponseUtility.cs b/DiagnosticsExtension/Models/ConnectionStringValidator/Exceptions/ConnectionStringResponseUtility.cs index a505c7ec..86d9eb6c 100644 --- a/DiagnosticsExtension/Models/ConnectionStringValidator/Exceptions/ConnectionStringResponseUtility.cs +++ b/DiagnosticsExtension/Models/ConnectionStringValidator/Exceptions/ConnectionStringResponseUtility.cs @@ -37,7 +37,6 @@ public static void EvaluateResponseStatus(Exception e, ConnectionStringType type response.Status = ConnectionStringValidationResult.ResultStatus.AuthFailure; response.StatusSummary = Constants.AuthenticationFailure; response.StatusDetails = Constants.AuthFailureDetails; - response.Exception = e; } else if (e.InnerException != null && @@ -98,6 +97,15 @@ public static void EvaluateResponseStatus(Exception e, ConnectionStringType type response.StatusDetails = Constants.AuthFailureDetails; response.Exception = e; } + else if ((e is Azure.RequestFailedException && e.Message.Contains("failed to authenticate")) || + e.Message.Contains("claim is empty or token is invalid") || + e.Message.Contains("InvalidSignature")) + { + response.Status = ConnectionStringValidationResult.ResultStatus.AuthFailure; + response.StatusSummary = Constants.AuthenticationFailure; + response.StatusDetails = Constants.AuthFailureDetails; + response.Exception = e; + } else if (e.Message.Contains("Ip has been prevented to connect to the endpoint")) { response.Status = ConnectionStringValidationResult.ResultStatus.Forbidden; @@ -120,6 +128,7 @@ public static void EvaluateResponseStatus(Exception e, ConnectionStringType type else { response.Status = ConnectionStringValidationResult.ResultStatus.UnknownError; + response.Exception = e; } } diff --git a/DiagnosticsExtension/Models/ConnectionStringValidator/Exceptions/ManagedIdentityConnectionResponseUtility.cs b/DiagnosticsExtension/Models/ConnectionStringValidator/Exceptions/ManagedIdentityConnectionResponseUtility.cs index 7b65e55b..ae0ab641 100644 --- a/DiagnosticsExtension/Models/ConnectionStringValidator/Exceptions/ManagedIdentityConnectionResponseUtility.cs +++ b/DiagnosticsExtension/Models/ConnectionStringValidator/Exceptions/ManagedIdentityConnectionResponseUtility.cs @@ -24,7 +24,6 @@ public static void EvaluateResponseStatus(Exception e, ConnectionStringType type response.Status = ConnectionStringValidationResult.ResultStatus.ManagedIdentityConnectionFailed; response.StatusSummary = ((ManagedIdentityException)e).MessageSummary; response.StatusDetails = ((ManagedIdentityException)e).MessageDetails; - response.Exception = e; } else if (e is UnauthorizedAccessException && e.Message.Contains("unauthorized") || e.Message.Contains("Unauthorized") || e.Message.Contains("request is not authorized")) { @@ -45,13 +44,11 @@ public static void EvaluateResponseStatus(Exception e, ConnectionStringType type { response.Status = ConnectionStringValidationResult.ResultStatus.ManagedIdentityNotConfigured; response.StatusSummary = "Your app is configured to use identity based connection but does not have a system assigned managed identity assigned. Refer here for details."; - response.Exception = e; } else if (e.Message.Contains("fullyQualifiedNamespace")) { response.Status = ConnectionStringValidationResult.ResultStatus.FullyQualifiedNamespaceMissing; - response.StatusSummary = "The app setting " + appSettingName + FullyQualifiedNamespace + " was not found or is set to a blank value. Refer here for details."; - response.Exception = e; + response.StatusSummary = "The app setting " + appSettingName + "__fullyQualifiedNamespace was not found or is set to a blank value. Refer here for details."; } else if (e.InnerException != null && e.InnerException.Message.Contains("The remote name could not be resolved")) // queue and blob @@ -67,6 +64,11 @@ public static void EvaluateResponseStatus(Exception e, ConnectionStringType type response.StatusDetails = String.Format(Constants.FQNamespaceResourceNotFound, appSettingName); response.Exception = e; } + else + { + response.Status = ConnectionStringValidationResult.ResultStatus.UnknownError; + response.Exception = e; + } } public static string ResolveManagedIdentityCommonProperty(string appSettingName, ConnectionStringValidationResult.ManagedIdentityCommonProperty prop) { diff --git a/DiagnosticsExtension/Models/ConnectionStringValidator/QueueStorageValidator.cs b/DiagnosticsExtension/Models/ConnectionStringValidator/QueueStorageValidator.cs index 95e959c5..4c5237a3 100644 --- a/DiagnosticsExtension/Models/ConnectionStringValidator/QueueStorageValidator.cs +++ b/DiagnosticsExtension/Models/ConnectionStringValidator/QueueStorageValidator.cs @@ -55,20 +55,21 @@ public async Task ValidateViaAppsettingAsync(s string serviceUriString = ManagedIdentityConnectionResponseUtility.ResolveManagedIdentityCommonProperty(appSettingName, ConnectionStringValidationResult.ManagedIdentityCommonProperty.queueServiceUri); if (!string.IsNullOrEmpty(serviceUriString)) { + string clientIdAppSettingKey = Environment.GetEnvironmentVariables().Keys.Cast().Where(k => k.StartsWith(appSettingName) && k.ToLower().EndsWith("clientid")).FirstOrDefault(); appSettingClientIdValue = ManagedIdentityConnectionResponseUtility.ResolveManagedIdentityCommonProperty(appSettingName, ConnectionStringValidationResult.ManagedIdentityCommonProperty.clientId); appSettingClientCredValue = ManagedIdentityConnectionResponseUtility.ResolveManagedIdentityCommonProperty(appSettingName, ConnectionStringValidationResult.ManagedIdentityCommonProperty.credential); + if (appSettingClientCredValue != null && appSettingClientCredValue != Constants.ValidCredentialValue) + { + throw new ManagedIdentityException(String.Format(Constants.ManagedIdentityCredentialInvalidSummary, appSettingName), Constants.ManagedIdentityCredentialInvalidDetails); + } Uri serviceUri = new Uri(serviceUriString); - // Creating client using User assigned managed identity - if (appSettingClientCredValue != null) + // If the user has configured __credential with "managedidentity" and set an app setting for __clientId (even if its empty) we assume their intent is to use a user assigned managed identity + if (appSettingClientCredValue != null && clientIdAppSettingKey != null) { - if (appSettingClientCredValue != Constants.ValidCredentialValue) - { - throw new ManagedIdentityException(String.Format(Constants.ManagedIdentityCredentialInvalidSummary, appSettingName), Constants.ManagedIdentityCredentialInvalidDetails); - } if (string.IsNullOrEmpty(appSettingClientIdValue)) { - throw new ManagedIdentityException(String.Format(Constants.ManagedIdentityClientIdNullOrEmptySummary, appSettingName), - String.Format(Constants.ManagedIdentityClientIdNullOrEmptyDetails, appSettingName)); + throw new ManagedIdentityException(String.Format(Constants.ManagedIdentityClientIdEmptySummary, appSettingName), + String.Format(Constants.ManagedIdentityClientIdEmptyDetails, appSettingName)); } response.IdentityType = Constants.User; client = new QueueServiceClient(serviceUri, ManagedIdentityCredentialTokenValidator.GetValidatedCredential(appSettingClientIdValue, appSettingName)); @@ -82,8 +83,14 @@ public async Task ValidateViaAppsettingAsync(s } else { - throw new ManagedIdentityException(String.Format(Constants.QueueServiceUriMissingSummary, appSettingName), - Constants.QueueServiceUriMissingDetails); + string serviceuriAppSettingName = Environment.GetEnvironmentVariables().Keys.Cast().Where(k => k.StartsWith(appSettingName) && k.ToLower().EndsWith("queueserviceuri")).FirstOrDefault(); + if (serviceuriAppSettingName == null) + { + throw new ManagedIdentityException(Constants.ConnectionInfoMissingSummary, + Constants.QueueServiceUriMissingDetails); + } + throw new ManagedIdentityException(String.Format(Constants.QueueServiceUriEmptySummary, appSettingName), + Constants.ServiceUriEmptyDetails); } } var resultSegment = diff --git a/DiagnosticsExtension/Models/ConnectionStringValidator/ServiceBusValidator.cs b/DiagnosticsExtension/Models/ConnectionStringValidator/ServiceBusValidator.cs index 34adb16a..0160f8a3 100644 --- a/DiagnosticsExtension/Models/ConnectionStringValidator/ServiceBusValidator.cs +++ b/DiagnosticsExtension/Models/ConnectionStringValidator/ServiceBusValidator.cs @@ -101,9 +101,17 @@ async public Task ValidateViaAppsettingAsync(s try { string connectionString = Environment.GetEnvironmentVariable(appSettingName); + if (string.IsNullOrEmpty(connectionString)) + { + throw new EmptyConnectionStringException(); + } connectionString += ";EntityPath=" + entityName; client = new ServiceBusClient(connectionString); } + catch (EmptyConnectionStringException e) + { + throw new EmptyConnectionStringException(e.Message, e); + } catch (Exception e) { throw new MalformedConnectionStringException(e.Message, e); @@ -113,28 +121,44 @@ async public Task ValidateViaAppsettingAsync(s { isManagedIdentityConnection = true; string serviceUriString = ManagedIdentityConnectionResponseUtility.ResolveManagedIdentityCommonProperty(appSettingName, ConnectionStringValidationResult.ManagedIdentityCommonProperty.fullyQualifiedNamespace); - appSettingClientIdValue = ManagedIdentityConnectionResponseUtility.ResolveManagedIdentityCommonProperty(appSettingName, ConnectionStringValidationResult.ManagedIdentityCommonProperty.clientId); - appSettingClientCredValue = ManagedIdentityConnectionResponseUtility.ResolveManagedIdentityCommonProperty(appSettingName, ConnectionStringValidationResult.ManagedIdentityCommonProperty.credential); - // Creating client using User assigned managed identity - if (appSettingClientCredValue != null) + if (!string.IsNullOrEmpty(serviceUriString)) { - if (appSettingClientCredValue != Constants.ValidCredentialValue) + string clientIdAppSettingKey = Environment.GetEnvironmentVariables().Keys.Cast().Where(k => k.StartsWith(appSettingName) && k.ToLower().EndsWith("clientid")).FirstOrDefault(); + appSettingClientIdValue = ManagedIdentityConnectionResponseUtility.ResolveManagedIdentityCommonProperty(appSettingName, ConnectionStringValidationResult.ManagedIdentityCommonProperty.clientId); + appSettingClientCredValue = ManagedIdentityConnectionResponseUtility.ResolveManagedIdentityCommonProperty(appSettingName, ConnectionStringValidationResult.ManagedIdentityCommonProperty.credential); + if (appSettingClientCredValue != null && appSettingClientCredValue != Constants.ValidCredentialValue) { throw new ManagedIdentityException(String.Format(Constants.ManagedIdentityCredentialInvalidSummary, appSettingName), Constants.ManagedIdentityCredentialInvalidDetails); } - if (string.IsNullOrEmpty(appSettingClientIdValue)) + // If the user has configured __credential with "managedidentity" and set an app setting for __clientId (even if its empty) we assume their intent is to use a user assigned managed identity + if (appSettingClientCredValue != null && clientIdAppSettingKey != null) { - throw new ManagedIdentityException(String.Format(Constants.ManagedIdentityClientIdNullOrEmptySummary, appSettingName), - String.Format(Constants.ManagedIdentityClientIdNullOrEmptyDetails, appSettingName)); + if (string.IsNullOrEmpty(appSettingClientIdValue)) + { + throw new ManagedIdentityException(String.Format(Constants.ManagedIdentityClientIdEmptySummary, appSettingName), + String.Format(Constants.ManagedIdentityClientIdEmptyDetails, appSettingName)); + } + response.IdentityType = Constants.User; + client = new ServiceBusClient(serviceUriString, ManagedIdentityCredentialTokenValidator.GetValidatedCredential(appSettingClientIdValue, appSettingName)); + } + // Creating client using System assigned managed identity + else + { + response.IdentityType = Constants.System; + client = new ServiceBusClient(serviceUriString, new Azure.Identity.ManagedIdentityCredential()); } - response.IdentityType = Constants.User; - client = new ServiceBusClient(serviceUriString, ManagedIdentityCredentialTokenValidator.GetValidatedCredential(appSettingClientIdValue, appSettingName)); } - // Creating client using System assigned managed identity else { - response.IdentityType = Constants.System; - client = new ServiceBusClient(serviceUriString, new Azure.Identity.ManagedIdentityCredential()); + string fullyQualifiedNamespaceAppSettingName = Environment.GetEnvironmentVariables().Keys.Cast().Where(k => k.StartsWith(appSettingName) && k.ToLower().EndsWith("fullyqualifiednamespace")).FirstOrDefault(); + if (fullyQualifiedNamespaceAppSettingName == null) + { + throw new ManagedIdentityException(Constants.ConnectionInfoMissingSummary, + Constants.ServiceBusFQMissingDetails); + } + throw new ManagedIdentityException(String.Format(Constants.FullyQualifiedNamespaceEmptySummary, fullyQualifiedNamespaceAppSettingName), + Constants.ServiceBusFQNSEmptyDetails); + } } ServiceBusReceiverOptions opt = new ServiceBusReceiverOptions(); From 3566ed8a1c8462a9e3289491acedceb225b2e7d4 Mon Sep 17 00:00:00 2001 From: Gajibilli Koteswara Rao Date: Tue, 5 Apr 2022 21:51:31 +0530 Subject: [PATCH 16/26] Code changes of latest comments on fobidden case --- .../ConnectionStringValidationResult.cs | 11 +++++ .../ConnectionStringValidator/Constants.cs | 6 +-- .../ConnectionStringResponseUtility.cs | 48 +++++++++++++++++++ 3 files changed, 62 insertions(+), 3 deletions(-) diff --git a/DiagnosticsExtension/Models/ConnectionStringValidator/ConnectionStringValidationResult.cs b/DiagnosticsExtension/Models/ConnectionStringValidator/ConnectionStringValidationResult.cs index 7cf67b53..b6d6600e 100644 --- a/DiagnosticsExtension/Models/ConnectionStringValidator/ConnectionStringValidationResult.cs +++ b/DiagnosticsExtension/Models/ConnectionStringValidator/ConnectionStringValidationResult.cs @@ -8,20 +8,31 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Text.Json.Serialization; using System.Web; +using System.Web.UI.WebControls; +using Newtonsoft.Json; namespace DiagnosticsExtension.Models.ConnectionStringValidator { public class ConnectionStringValidationResult { + [Newtonsoft.Json.JsonIgnore] public ResultStatus? Status; + [Newtonsoft.Json.JsonIgnore] public string IdentityType; + [JsonProperty("Summary")] public string StatusSummary; + [JsonProperty("Details")] public string StatusDetails; public string StatusText => Status?.ToString(); + [Newtonsoft.Json.JsonIgnore] public Exception Exception; + public string ExceptionMessage => Exception?.Message; + [Newtonsoft.Json.JsonIgnore] public object Payload; + [Newtonsoft.Json.JsonIgnore] public string Type => type.ToString(); private ConnectionStringType type; diff --git a/DiagnosticsExtension/Models/ConnectionStringValidator/Constants.cs b/DiagnosticsExtension/Models/ConnectionStringValidator/Constants.cs index af572749..652435c2 100644 --- a/DiagnosticsExtension/Models/ConnectionStringValidator/Constants.cs +++ b/DiagnosticsExtension/Models/ConnectionStringValidator/Constants.cs @@ -32,7 +32,6 @@ public static class Constants public const string ServiceUriEmptyDetails = "Refer here for relevant configuration details. " + ManagedIdentityTutorial; public const string ServiceBusFQNSEmptyDetails = "Refer here for relevant configuration details. " + ManagedIdentityTutorial; public const string EventHubFQNSEmptyDetails = "Refer here for relevant configuration details. " + ManagedIdentityTutorial; - public const string ServiceUriEmpty = "ServiceUriEmpty"; public const string QueueServiceUriMissingSummary = "The app setting {0}__queueServiceUri is not configured or has an empty value."; public const string QueueServiceUriMissingDetails = "To connect to your storage account, you need to provide a connection string or use identity-based connections. To learn more please refer here. " + ManagedIdentityTutorial; @@ -43,7 +42,6 @@ public static class Constants public const string ManagedIdentityClientIdNullOrEmptyDetails = "When the app setting {0}" + Credential + " is configured to \"managedidentity\", the clientId of a user assigned managed identity assigned to the Function App is expected in the app setting {0}" + ClientId + ". Refer here for details. " + ManagedIdentityTutorial; public const string ManagedIdentityClientIdEmptySummary = "The app setting {0}" + ClientId + " has an empty value."; public const string ManagedIdentityClientIdEmptyDetails = "When the app setting {0}" + Credential + " is configured to \"managedidentity\", the clientId of a user assigned managed identity assigned to the Function App is expected in the app setting {0}" + ClientId + ". Refer here for details. " + ManagedIdentityTutorial; - public const string AuthorizationFailure = "Authorization failure"; public const string AuthenticationFailure = "Authentication failure"; public const string InvalidConnection = "Invalid connection string"; @@ -52,8 +50,10 @@ public static class Constants public const string ClientIdInvalidTokenGeneratedDetails = "Refer here for details related to configuring connections via managed identity. " + ManagedIdentityTutorial; public const string SystemAssignedAuthFailure = "The system assigned managed identity for this Function App does not have access to the resource configured in {0}. Refer here for details around configuring connections via managed identity. " + ManagedIdentityTutorial; public const string UserAssignedAuthFailure = "The configured user assigned managed identity does not have access to the resource configured in {0}. Refer here for details around configuring connections via managed identity. " + ManagedIdentityTutorial; - public const string AuthFailureDetails = "Authentication failure - the credentials in the configured connection string are either invalid or expired. Please update the app setting with a valid connection string."; + public const string StorageAccessRestrictedDetails = "This can be due to firewall rules on the resource. Please check if you have configured firewall rules or a private endpoint and that they correctly allow access from the Function App. Relevant documentation:

Storage account network security"; + public const string ServiceBusAccessRestrictedDetails = "This can be due to firewall rules on the resource. Please check if you have configured firewall rules or a private endpoint and that they correctly allow access from the Function App. Relevant documentation:

Service Bus network security"; + public const string EventHubAccessRestrictedDetails = "This can be due to firewall rules on the resource. Please check if you have configured firewall rules or a private endpoint and that they correctly allow access from the Function App. Relevant documentation:

Event Hubs network security"; public const string DnsLookupFailedDetails = "The service resource specified in the connection string was not found. Please check the value of the setting."; public const string FQNamespaceResourceNotFound = "The resource specified in the app setting {0}" + FullyQualifiedNamespace + " was not found. Please check the value of the setting."; public const string StorageAccountResourceNotFound = "The resource specified in the app setting {0} was not found. Please check the value of the setting."; diff --git a/DiagnosticsExtension/Models/ConnectionStringValidator/Exceptions/ConnectionStringResponseUtility.cs b/DiagnosticsExtension/Models/ConnectionStringValidator/Exceptions/ConnectionStringResponseUtility.cs index 86d9eb6c..fdae5a0b 100644 --- a/DiagnosticsExtension/Models/ConnectionStringValidator/Exceptions/ConnectionStringResponseUtility.cs +++ b/DiagnosticsExtension/Models/ConnectionStringValidator/Exceptions/ConnectionStringResponseUtility.cs @@ -109,6 +109,30 @@ public static void EvaluateResponseStatus(Exception e, ConnectionStringType type else if (e.Message.Contains("Ip has been prevented to connect to the endpoint")) { response.Status = ConnectionStringValidationResult.ResultStatus.Forbidden; + if (e.Message.Contains("AuthenticationFailed")) + { + response.StatusSummary = Constants.AuthenticationFailure; + response.StatusDetails = Constants.AuthFailureDetails; + } + else + { + response.StatusSummary = "Access to the "+ type +" resource is restricted."; + switch (type) + { + case ConnectionStringType.ServiceBus: + response.StatusDetails = Constants.ServiceBusAccessRestrictedDetails; + break; + case ConnectionStringType.EventHubs: + response.StatusDetails = Constants.EventHubAccessRestrictedDetails; + break; + case ConnectionStringType.StorageAccount: + case ConnectionStringType.BlobStorageAccount: + case ConnectionStringType.QueueStorageAccount: + case ConnectionStringType.FileShareStorageAccount: + response.StatusDetails = Constants.StorageAccessRestrictedDetails; + break; + } + } response.Exception = e; } else if (e is StorageException) @@ -122,6 +146,30 @@ public static void EvaluateResponseStatus(Exception e, ConnectionStringType type else if (((StorageException)e).RequestInformation.HttpStatusCode == 403) { response.Status = ConnectionStringValidationResult.ResultStatus.Forbidden; + if (e.Message.Contains("AuthenticationFailed")) + { + response.StatusSummary = Constants.AuthenticationFailure; + response.StatusDetails = Constants.AuthFailureDetails; + } + else + { + response.StatusSummary = "Access to the " + type + " resource is restricted."; + switch (type) + { + case ConnectionStringType.ServiceBus: + response.StatusDetails = Constants.ServiceBusAccessRestrictedDetails; + break; + case ConnectionStringType.EventHubs: + response.StatusDetails = Constants.EventHubAccessRestrictedDetails; + break; + case ConnectionStringType.StorageAccount: + case ConnectionStringType.BlobStorageAccount: + case ConnectionStringType.QueueStorageAccount: + case ConnectionStringType.FileShareStorageAccount: + response.StatusDetails = Constants.StorageAccessRestrictedDetails; + break; + } + } } response.Exception = e; } From 1dc127958207d75fd2f591be49d5a2d981fff064 Mon Sep 17 00:00:00 2001 From: Sid Krishna Date: Thu, 7 Apr 2022 03:16:02 -0700 Subject: [PATCH 17/26] Improved error and mitigation messages and fixed a few relevant bugs I found while reviewing the messages. --- .../BlobStorageValidator.cs | 10 ++-- .../ConnectionStringValidator/Constants.cs | 53 ++++++++----------- .../EventHubsValidator.cs | 10 ++-- .../ConnectionStringResponseUtility.cs | 21 ++++---- ...anagedIdentityConnectionResponseUtility.cs | 4 +- .../Exceptions/ManagedIdentityException.cs | 2 +- ...ManagedIdentityCredentialTokenValidator.cs | 3 +- .../QueueStorageValidator.cs | 10 ++-- .../ServiceBusValidator.cs | 10 ++-- 9 files changed, 51 insertions(+), 72 deletions(-) diff --git a/DiagnosticsExtension/Models/ConnectionStringValidator/BlobStorageValidator.cs b/DiagnosticsExtension/Models/ConnectionStringValidator/BlobStorageValidator.cs index 33e9d58e..191552e7 100644 --- a/DiagnosticsExtension/Models/ConnectionStringValidator/BlobStorageValidator.cs +++ b/DiagnosticsExtension/Models/ConnectionStringValidator/BlobStorageValidator.cs @@ -66,7 +66,7 @@ public async Task ValidateViaAppsettingAsync(s appSettingClientCredValue = ManagedIdentityConnectionResponseUtility.ResolveManagedIdentityCommonProperty(appSettingName, ConnectionStringValidationResult.ManagedIdentityCommonProperty.credential); if (appSettingClientCredValue != null && appSettingClientCredValue != Constants.ValidCredentialValue) { - throw new ManagedIdentityException(String.Format(Constants.ManagedIdentityCredentialInvalidSummary, appSettingName), Constants.ManagedIdentityCredentialInvalidDetails); + throw new ManagedIdentityException(String.Format(Constants.ManagedIdentityCredentialInvalidSummary, appSettingName)); } Uri serviceUri = new Uri(serviceUriString); // If the user has configured __credential with "managedidentity" and set an app setting for __clientId (even if its empty) we assume their intent is to use a user assigned managed identity @@ -74,7 +74,7 @@ public async Task ValidateViaAppsettingAsync(s { if (string.IsNullOrEmpty(appSettingClientIdValue)) { - throw new ManagedIdentityException(String.Format(Constants.ManagedIdentityClientIdEmptySummary, appSettingName), + throw new ManagedIdentityException(String.Format(Constants.ManagedIdentityClientIdEmptySummary, clientIdAppSettingKey), String.Format(Constants.ManagedIdentityClientIdEmptyDetails, appSettingName)); } response.IdentityType = Constants.User; @@ -92,11 +92,9 @@ public async Task ValidateViaAppsettingAsync(s string serviceuriAppSettingName = Environment.GetEnvironmentVariables().Keys.Cast().Where(k => k.StartsWith(appSettingName) && k.ToLower().EndsWith("serviceuri")).FirstOrDefault(); if (serviceuriAppSettingName == null) { - throw new ManagedIdentityException(Constants.ConnectionInfoMissingSummary, - Constants.BlobServiceUriMissingDetails); + throw new ManagedIdentityException(Constants.BlobServiceUriMissingSummary); } - throw new ManagedIdentityException(String.Format(Constants.BlobServiceUriEmptySummary, serviceuriAppSettingName), - Constants.ServiceUriEmptyDetails); + throw new ManagedIdentityException(String.Format(Constants.BlobServiceUriEmptySummary, serviceuriAppSettingName)); } } diff --git a/DiagnosticsExtension/Models/ConnectionStringValidator/Constants.cs b/DiagnosticsExtension/Models/ConnectionStringValidator/Constants.cs index 652435c2..cb4410e8 100644 --- a/DiagnosticsExtension/Models/ConnectionStringValidator/Constants.cs +++ b/DiagnosticsExtension/Models/ConnectionStringValidator/Constants.cs @@ -21,45 +21,36 @@ public static class Constants public const string ColonSeparator = ":"; public const string ClientId = "__clientId"; public const string Credential = "__credential"; - public const string ManagedIdentityTutorial = "A relevant tutorial is also available here."; - public const string ConnectionInfoMissingSummary = "Necessary connection information was not found"; - public const string BlobServiceUriMissingDetails = "To connect to your storage account, you need to provide a connection string or use identity-based connections. To learn more please refer here. " + ManagedIdentityTutorial; - public const string ServiceBusFQMissingDetails = "To connect to your service bus, you need to provide a connection string or use identity-based connections. To learn more please refer here. " + ManagedIdentityTutorial; - public const string EventHubFQMissingDetails = "To connect to your event hub, you need to provide a connection string or use identity-based connections. To learn more please refer here. " + ManagedIdentityTutorial; - public const string FullyQualifiedNamespaceEmptySummary = "The app setting {0} has an empty value."; - public const string BlobServiceUriEmptySummary = "The app setting {0} has an empty value."; - public const string QueueServiceUriEmptySummary = "The app setting {0}__queueServiceUri has an empty value."; - public const string ServiceUriEmptyDetails = "Refer here for relevant configuration details. " + ManagedIdentityTutorial; - public const string ServiceBusFQNSEmptyDetails = "Refer here for relevant configuration details. " + ManagedIdentityTutorial; - public const string EventHubFQNSEmptyDetails = "Refer here for relevant configuration details. " + ManagedIdentityTutorial; - public const string ServiceUriEmpty = "ServiceUriEmpty"; - public const string QueueServiceUriMissingSummary = "The app setting {0}__queueServiceUri is not configured or has an empty value."; - public const string QueueServiceUriMissingDetails = "To connect to your storage account, you need to provide a connection string or use identity-based connections. To learn more please refer here. " + ManagedIdentityTutorial; public const string QueueServiceUri = "__queueServiceUri"; public const string ValidCredentialValue = "managedidentity"; public const string FullyQualifiedNamespace = "__fullyQualifiedNamespace"; - public const string ManagedIdentityClientIdNullOrEmptySummary = "The app setting {0}" + ClientId + " was expected but not found."; - public const string ManagedIdentityClientIdNullOrEmptyDetails = "When the app setting {0}" + Credential + " is configured to \"managedidentity\", the clientId of a user assigned managed identity assigned to the Function App is expected in the app setting {0}" + ClientId + ". Refer here for details. " + ManagedIdentityTutorial; - public const string ManagedIdentityClientIdEmptySummary = "The app setting {0}" + ClientId + " has an empty value."; - public const string ManagedIdentityClientIdEmptyDetails = "When the app setting {0}" + Credential + " is configured to \"managedidentity\", the clientId of a user assigned managed identity assigned to the Function App is expected in the app setting {0}" + ClientId + ". Refer here for details. " + ManagedIdentityTutorial; + public const string GenericDetailsMessage = "Additional details of the error."; + public const string ManagedIdentityTutorial = "Here is a relevant tutorial."; + public const string BlobServiceUriMissingSummary = "Necessary connection settings not found. A connection string or identity-based connection settings are required. See relevant docs. "; + public const string QueueServiceUriMissingSummary = "Necessary connection settings not found. A connection string or identity-based connection settings are required. See relevant docs. "; + public const string ServiceBusFQMissingSummary = "Necessary connection settings not found. A connection string or identity-based connection settings are required. See relevant docs. "; + public const string EventHubFQMissingSummary = "Necessary connection settings not found. A connection string or identity-based connection settings are required. See relevant docs. "; + public const string BlobServiceUriEmptySummary = "The app setting {0} has no value. See relevant docs. " + ManagedIdentityTutorial; + public const string QueueServiceUriEmptySummary = "The app setting {0} has no value. See relevant docs. " + ManagedIdentityTutorial; + public const string ServiceBusFQNSEmptySummary = "The app setting {0} has no value. See relevant docs. " + ManagedIdentityTutorial; + public const string EventHubFQNSEmptySummary = "The app setting {0} has no value. See relevant docs. " + ManagedIdentityTutorial; + public const string ManagedIdentityClientIdEmptySummary = "The app setting {0} has no value."; + public const string ManagedIdentityClientIdEmptyDetails = "When the app setting {0}" + Credential + " is configured to \"managedidentity\", the clientId of a user assigned managed identity assigned to the Function App is expected in the app setting {0}" + ClientId + ". See relevant docs. " + ManagedIdentityTutorial; public const string AuthorizationFailure = "Authorization failure"; public const string AuthenticationFailure = "Authentication failure"; - public const string InvalidConnection = "Invalid connection string"; - public const string ResourceNotFound = "Resource not found"; - public const string ClientIdInvalidTokenGeneratedSummary = "The ClientId configured in the app setting {0}" + ClientId + " does not match any user assigned managed identity assigned to this app."; - public const string ClientIdInvalidTokenGeneratedDetails = "Refer here for details related to configuring connections via managed identity. " + ManagedIdentityTutorial; - public const string SystemAssignedAuthFailure = "The system assigned managed identity for this Function App does not have access to the resource configured in {0}. Refer here for details around configuring connections via managed identity. " + ManagedIdentityTutorial; - public const string UserAssignedAuthFailure = "The configured user assigned managed identity does not have access to the resource configured in {0}. Refer here for details around configuring connections via managed identity. " + ManagedIdentityTutorial; + public const string ClientIdInvalidTokenGeneratedSummary = "The value of app setting {0}" + ClientId + " does not match any user assigned managed identity assigned to this app. See relevant docs. " + ManagedIdentityTutorial; + public const string SystemAssignedAuthFailure = "The system assigned managed identity for this Function App does not have access to the resource configured in {0}. See relevant docs. " + ManagedIdentityTutorial; + public const string UserAssignedAuthFailure = "The configured user assigned managed identity does not have access to the resource configured in {0}. See relevant docs. " + ManagedIdentityTutorial; + // TODO: Update this with relevant documentation link and create resource type specific variants. public const string AuthFailureDetails = "Authentication failure - the credentials in the configured connection string are either invalid or expired. Please update the app setting with a valid connection string."; - public const string StorageAccessRestrictedDetails = "This can be due to firewall rules on the resource. Please check if you have configured firewall rules or a private endpoint and that they correctly allow access from the Function App. Relevant documentation:

Storage account network security"; - public const string ServiceBusAccessRestrictedDetails = "This can be due to firewall rules on the resource. Please check if you have configured firewall rules or a private endpoint and that they correctly allow access from the Function App. Relevant documentation:

Service Bus network security"; - public const string EventHubAccessRestrictedDetails = "This can be due to firewall rules on the resource. Please check if you have configured firewall rules or a private endpoint and that they correctly allow access from the Function App. Relevant documentation:

Event Hubs network security"; - public const string DnsLookupFailedDetails = "The service resource specified in the connection string was not found. Please check the value of the setting."; + public const string StorageAccessRestrictedDetails = "This can be due to firewall rules on the resource. Please check if you have configured firewall rules or a private endpoint and that they correctly allow access from the Function App. See Storage account network security for additional details."; + public const string ServiceBusAccessRestrictedDetails = "This can be due to firewall rules on the resource. Please check if you have configured firewall rules or a private endpoint and that they correctly allow access from the Function App. See Service Bus network security for additional details."; + public const string EventHubAccessRestrictedDetails = "This can be due to firewall rules on the resource. Please check if you have configured firewall rules or a private endpoint and that they correctly allow access from the Function App. See Event Hubs network security for additional details."; + public const string DnsLookupFailed = "The service resource specified in the connection string was not found. Please check the value of the setting."; public const string FQNamespaceResourceNotFound = "The resource specified in the app setting {0}" + FullyQualifiedNamespace + " was not found. Please check the value of the setting."; public const string StorageAccountResourceNotFound = "The resource specified in the app setting {0} was not found. Please check the value of the setting."; - public const string MalformedConnectionStringDetails = "The connection string configured is invalid(e.g.missing some required elements). Please check the value configured in the app setting "; - public const string ManagedIdentityCredentialInvalidSummary = "The app setting {0}" + Credential + " is defined but not valid. To use identity based connections, set it's value to \"managedidentity\"."; - public const string ManagedIdentityCredentialInvalidDetails = "Refer here for more information about configuring this app setting. " + ManagedIdentityTutorial; + public const string MalformedConnectionStringDetails = "The connection string configured in app setting {0} is invalid (e.g.missing some required elements)."; + public const string ManagedIdentityCredentialInvalidSummary = "The app setting {0}" + Credential + " is not valid. To use identity based connections, set it's value to \"managedidentity\". See relevant docs. " + ManagedIdentityTutorial; #endregion } } diff --git a/DiagnosticsExtension/Models/ConnectionStringValidator/EventHubsValidator.cs b/DiagnosticsExtension/Models/ConnectionStringValidator/EventHubsValidator.cs index cc294236..5fc7e652 100644 --- a/DiagnosticsExtension/Models/ConnectionStringValidator/EventHubsValidator.cs +++ b/DiagnosticsExtension/Models/ConnectionStringValidator/EventHubsValidator.cs @@ -115,14 +115,14 @@ async public Task ValidateViaAppsettingAsync(s appSettingClientCredValue = ManagedIdentityConnectionResponseUtility.ResolveManagedIdentityCommonProperty(appSettingName, ConnectionStringValidationResult.ManagedIdentityCommonProperty.credential); if (appSettingClientCredValue != null && appSettingClientCredValue != Constants.ValidCredentialValue) { - throw new ManagedIdentityException(String.Format(Constants.ManagedIdentityCredentialInvalidSummary, appSettingName), Constants.ManagedIdentityCredentialInvalidDetails); + throw new ManagedIdentityException(String.Format(Constants.ManagedIdentityCredentialInvalidSummary, appSettingName)); } // If the user has configured __credential with "managedidentity" and set an app setting for __clientId (even if its empty) we assume their intent is to use a user assigned managed identity if (appSettingClientCredValue != null && clientIdAppSettingKey != null) { if (string.IsNullOrEmpty(appSettingClientIdValue)) { - throw new ManagedIdentityException(String.Format(Constants.ManagedIdentityClientIdEmptySummary, appSettingName), + throw new ManagedIdentityException(String.Format(Constants.ManagedIdentityClientIdEmptySummary, clientIdAppSettingKey), String.Format(Constants.ManagedIdentityClientIdEmptyDetails, appSettingName)); } response.IdentityType = Constants.User; @@ -140,11 +140,9 @@ async public Task ValidateViaAppsettingAsync(s string fullyQualifiedNamespaceAppSettingName = Environment.GetEnvironmentVariables().Keys.Cast().Where(k => k.StartsWith(appSettingName) && k.ToLower().EndsWith("fullyqualifiednamespace")).FirstOrDefault(); if (fullyQualifiedNamespaceAppSettingName == null) { - throw new ManagedIdentityException(Constants.ConnectionInfoMissingSummary, - Constants.EventHubFQMissingDetails); + throw new ManagedIdentityException(Constants.EventHubFQMissingSummary); } - throw new ManagedIdentityException(String.Format(Constants.FullyQualifiedNamespaceEmptySummary, fullyQualifiedNamespaceAppSettingName), - Constants.EventHubFQNSEmptyDetails); + throw new ManagedIdentityException(String.Format(Constants.EventHubFQNSEmptySummary, fullyQualifiedNamespaceAppSettingName)); } } diff --git a/DiagnosticsExtension/Models/ConnectionStringValidator/Exceptions/ConnectionStringResponseUtility.cs b/DiagnosticsExtension/Models/ConnectionStringValidator/Exceptions/ConnectionStringResponseUtility.cs index fdae5a0b..502e0d2c 100644 --- a/DiagnosticsExtension/Models/ConnectionStringValidator/Exceptions/ConnectionStringResponseUtility.cs +++ b/DiagnosticsExtension/Models/ConnectionStringValidator/Exceptions/ConnectionStringResponseUtility.cs @@ -22,8 +22,8 @@ public static void EvaluateResponseStatus(Exception e, ConnectionStringType type if (e is MalformedConnectionStringException) { response.Status = ConnectionStringValidationResult.ResultStatus.MalformedConnectionString; - response.StatusSummary = Constants.InvalidConnection; - response.StatusDetails = Constants.MalformedConnectionStringDetails + appSettingName; + response.StatusSummary = String.Format(Constants.MalformedConnectionStringDetails, appSettingName); + response.StatusDetails = Constants.GenericDetailsMessage; response.Exception = e; } else if (e is EmptyConnectionStringException) @@ -43,23 +43,20 @@ public static void EvaluateResponseStatus(Exception e, ConnectionStringType type e.InnerException.Message.Contains("The remote name could not be resolved")) { response.Status = ConnectionStringValidationResult.ResultStatus.DnsLookupFailed; - response.StatusSummary = Constants.ResourceNotFound; - response.StatusDetails = Constants.DnsLookupFailedDetails; + response.StatusSummary = Constants.DnsLookupFailed; response.Exception = e; } else if (e.InnerException != null && e.InnerException.InnerException != null && e.InnerException.InnerException.Message.Contains("The remote name could not be resolved")) { response.Status = ConnectionStringValidationResult.ResultStatus.DnsLookupFailed; - response.StatusSummary = Constants.ResourceNotFound; - response.StatusDetails = Constants.DnsLookupFailedDetails; + response.StatusSummary = Constants.DnsLookupFailed; response.Exception = e; } else if (e.Message.Contains("No such host is known")) { response.Status = ConnectionStringValidationResult.ResultStatus.DnsLookupFailed; - response.StatusSummary = Constants.ResourceNotFound; - response.StatusDetails = Constants.DnsLookupFailedDetails; + response.StatusSummary = Constants.DnsLookupFailed; response.Exception = e; } else if (e is ArgumentNullException || @@ -67,8 +64,8 @@ public static void EvaluateResponseStatus(Exception e, ConnectionStringType type e.Message.Contains("was not found")) { response.Status = ConnectionStringValidationResult.ResultStatus.MalformedConnectionString; - response.StatusSummary = Constants.InvalidConnection; - response.StatusDetails = Constants.MalformedConnectionStringDetails; + response.StatusSummary = String.Format(Constants.MalformedConnectionStringDetails, appSettingName); + response.StatusDetails = Constants.GenericDetailsMessage; response.Exception = e; } else if (e is ArgumentException && e.Message.Contains("entityPath is null") || @@ -77,8 +74,8 @@ public static void EvaluateResponseStatus(Exception e, ConnectionStringType type e.Message.Contains("The argument is null or white space")) { response.Status = ConnectionStringValidationResult.ResultStatus.MalformedConnectionString; - response.StatusSummary = Constants.InvalidConnection; - response.StatusDetails = Constants.MalformedConnectionStringDetails; + response.StatusSummary = String.Format(Constants.MalformedConnectionStringDetails, appSettingName); + response.StatusDetails = Constants.GenericDetailsMessage; response.Exception = e; } else if (e.Message.Contains("InvalidSignature")) diff --git a/DiagnosticsExtension/Models/ConnectionStringValidator/Exceptions/ManagedIdentityConnectionResponseUtility.cs b/DiagnosticsExtension/Models/ConnectionStringValidator/Exceptions/ManagedIdentityConnectionResponseUtility.cs index ae0ab641..6176e891 100644 --- a/DiagnosticsExtension/Models/ConnectionStringValidator/Exceptions/ManagedIdentityConnectionResponseUtility.cs +++ b/DiagnosticsExtension/Models/ConnectionStringValidator/Exceptions/ManagedIdentityConnectionResponseUtility.cs @@ -60,8 +60,8 @@ public static void EvaluateResponseStatus(Exception e, ConnectionStringType type else if (e.Message.Contains("No such host is known")) // event hub and service bus { response.Status = ConnectionStringValidationResult.ResultStatus.DnsLookupFailed; - response.StatusSummary = Constants.ResourceNotFound; - response.StatusDetails = String.Format(Constants.FQNamespaceResourceNotFound, appSettingName); + response.StatusSummary = String.Format(Constants.FQNamespaceResourceNotFound, appSettingName); + response.StatusDetails = Constants.GenericDetailsMessage; response.Exception = e; } else diff --git a/DiagnosticsExtension/Models/ConnectionStringValidator/Exceptions/ManagedIdentityException.cs b/DiagnosticsExtension/Models/ConnectionStringValidator/Exceptions/ManagedIdentityException.cs index 0dd6e0c9..ef4fdd7a 100644 --- a/DiagnosticsExtension/Models/ConnectionStringValidator/Exceptions/ManagedIdentityException.cs +++ b/DiagnosticsExtension/Models/ConnectionStringValidator/Exceptions/ManagedIdentityException.cs @@ -21,7 +21,7 @@ public ManagedIdentityException() : base() { } - public ManagedIdentityException(string summary, string details) : base() + public ManagedIdentityException(string summary, string details = null) : base() { this.MessageSummary = summary; this.MessageDetails = details; diff --git a/DiagnosticsExtension/Models/ConnectionStringValidator/ManagedIdentityCredentialTokenValidator.cs b/DiagnosticsExtension/Models/ConnectionStringValidator/ManagedIdentityCredentialTokenValidator.cs index 32f0c749..bef8db68 100644 --- a/DiagnosticsExtension/Models/ConnectionStringValidator/ManagedIdentityCredentialTokenValidator.cs +++ b/DiagnosticsExtension/Models/ConnectionStringValidator/ManagedIdentityCredentialTokenValidator.cs @@ -30,8 +30,7 @@ public static ManagedIdentityCredential GetValidatedCredential(string clientId, if (appId != clientId) { - throw new ManagedIdentityException(String.Format(Constants.ClientIdInvalidTokenGeneratedSummary,appSettingName), - Constants.ClientIdInvalidTokenGeneratedDetails); + throw new ManagedIdentityException(String.Format(Constants.ClientIdInvalidTokenGeneratedSummary, appSettingName)); } return tokenCredential; diff --git a/DiagnosticsExtension/Models/ConnectionStringValidator/QueueStorageValidator.cs b/DiagnosticsExtension/Models/ConnectionStringValidator/QueueStorageValidator.cs index 4c5237a3..4a24095f 100644 --- a/DiagnosticsExtension/Models/ConnectionStringValidator/QueueStorageValidator.cs +++ b/DiagnosticsExtension/Models/ConnectionStringValidator/QueueStorageValidator.cs @@ -60,7 +60,7 @@ public async Task ValidateViaAppsettingAsync(s appSettingClientCredValue = ManagedIdentityConnectionResponseUtility.ResolveManagedIdentityCommonProperty(appSettingName, ConnectionStringValidationResult.ManagedIdentityCommonProperty.credential); if (appSettingClientCredValue != null && appSettingClientCredValue != Constants.ValidCredentialValue) { - throw new ManagedIdentityException(String.Format(Constants.ManagedIdentityCredentialInvalidSummary, appSettingName), Constants.ManagedIdentityCredentialInvalidDetails); + throw new ManagedIdentityException(String.Format(Constants.ManagedIdentityCredentialInvalidSummary, appSettingName)); } Uri serviceUri = new Uri(serviceUriString); // If the user has configured __credential with "managedidentity" and set an app setting for __clientId (even if its empty) we assume their intent is to use a user assigned managed identity @@ -68,7 +68,7 @@ public async Task ValidateViaAppsettingAsync(s { if (string.IsNullOrEmpty(appSettingClientIdValue)) { - throw new ManagedIdentityException(String.Format(Constants.ManagedIdentityClientIdEmptySummary, appSettingName), + throw new ManagedIdentityException(String.Format(Constants.ManagedIdentityClientIdEmptySummary, clientIdAppSettingKey), String.Format(Constants.ManagedIdentityClientIdEmptyDetails, appSettingName)); } response.IdentityType = Constants.User; @@ -86,11 +86,9 @@ public async Task ValidateViaAppsettingAsync(s string serviceuriAppSettingName = Environment.GetEnvironmentVariables().Keys.Cast().Where(k => k.StartsWith(appSettingName) && k.ToLower().EndsWith("queueserviceuri")).FirstOrDefault(); if (serviceuriAppSettingName == null) { - throw new ManagedIdentityException(Constants.ConnectionInfoMissingSummary, - Constants.QueueServiceUriMissingDetails); + throw new ManagedIdentityException(Constants.QueueServiceUriMissingSummary); } - throw new ManagedIdentityException(String.Format(Constants.QueueServiceUriEmptySummary, appSettingName), - Constants.ServiceUriEmptyDetails); + throw new ManagedIdentityException(String.Format(Constants.QueueServiceUriEmptySummary, appSettingName)); } } var resultSegment = diff --git a/DiagnosticsExtension/Models/ConnectionStringValidator/ServiceBusValidator.cs b/DiagnosticsExtension/Models/ConnectionStringValidator/ServiceBusValidator.cs index 0160f8a3..90c0cf18 100644 --- a/DiagnosticsExtension/Models/ConnectionStringValidator/ServiceBusValidator.cs +++ b/DiagnosticsExtension/Models/ConnectionStringValidator/ServiceBusValidator.cs @@ -128,14 +128,14 @@ async public Task ValidateViaAppsettingAsync(s appSettingClientCredValue = ManagedIdentityConnectionResponseUtility.ResolveManagedIdentityCommonProperty(appSettingName, ConnectionStringValidationResult.ManagedIdentityCommonProperty.credential); if (appSettingClientCredValue != null && appSettingClientCredValue != Constants.ValidCredentialValue) { - throw new ManagedIdentityException(String.Format(Constants.ManagedIdentityCredentialInvalidSummary, appSettingName), Constants.ManagedIdentityCredentialInvalidDetails); + throw new ManagedIdentityException(String.Format(Constants.ManagedIdentityCredentialInvalidSummary, appSettingName)); } // If the user has configured __credential with "managedidentity" and set an app setting for __clientId (even if its empty) we assume their intent is to use a user assigned managed identity if (appSettingClientCredValue != null && clientIdAppSettingKey != null) { if (string.IsNullOrEmpty(appSettingClientIdValue)) { - throw new ManagedIdentityException(String.Format(Constants.ManagedIdentityClientIdEmptySummary, appSettingName), + throw new ManagedIdentityException(String.Format(Constants.ManagedIdentityClientIdEmptySummary, clientIdAppSettingKey), String.Format(Constants.ManagedIdentityClientIdEmptyDetails, appSettingName)); } response.IdentityType = Constants.User; @@ -153,11 +153,9 @@ async public Task ValidateViaAppsettingAsync(s string fullyQualifiedNamespaceAppSettingName = Environment.GetEnvironmentVariables().Keys.Cast().Where(k => k.StartsWith(appSettingName) && k.ToLower().EndsWith("fullyqualifiednamespace")).FirstOrDefault(); if (fullyQualifiedNamespaceAppSettingName == null) { - throw new ManagedIdentityException(Constants.ConnectionInfoMissingSummary, - Constants.ServiceBusFQMissingDetails); + throw new ManagedIdentityException(Constants.ServiceBusFQMissingSummary); } - throw new ManagedIdentityException(String.Format(Constants.FullyQualifiedNamespaceEmptySummary, fullyQualifiedNamespaceAppSettingName), - Constants.ServiceBusFQNSEmptyDetails); + throw new ManagedIdentityException(String.Format(Constants.ServiceBusFQNSEmptySummary, fullyQualifiedNamespaceAppSettingName)); } } From 25cb2617c7a6bf826c7531ca84077fa2a1fc96f8 Mon Sep 17 00:00:00 2001 From: Sid Krishna Date: Fri, 8 Apr 2022 02:56:10 -0700 Subject: [PATCH 18/26] Updated Authentication failed error messages with docs links --- .../ConnectionStringValidator/Constants.cs | 10 ++-- .../ConnectionStringResponseUtility.cs | 46 +++++++++++++------ 2 files changed, 39 insertions(+), 17 deletions(-) diff --git a/DiagnosticsExtension/Models/ConnectionStringValidator/Constants.cs b/DiagnosticsExtension/Models/ConnectionStringValidator/Constants.cs index cb4410e8..05ecddf5 100644 --- a/DiagnosticsExtension/Models/ConnectionStringValidator/Constants.cs +++ b/DiagnosticsExtension/Models/ConnectionStringValidator/Constants.cs @@ -24,7 +24,7 @@ public static class Constants public const string QueueServiceUri = "__queueServiceUri"; public const string ValidCredentialValue = "managedidentity"; public const string FullyQualifiedNamespace = "__fullyQualifiedNamespace"; - public const string GenericDetailsMessage = "Additional details of the error."; + public const string GenericDetailsMessage = "Additional details of the error:"; public const string ManagedIdentityTutorial = "Here is a relevant tutorial."; public const string BlobServiceUriMissingSummary = "Necessary connection settings not found. A connection string or identity-based connection settings are required. See relevant docs. "; public const string QueueServiceUriMissingSummary = "Necessary connection settings not found. A connection string or identity-based connection settings are required. See relevant docs. "; @@ -41,8 +41,12 @@ public static class Constants public const string ClientIdInvalidTokenGeneratedSummary = "The value of app setting {0}" + ClientId + " does not match any user assigned managed identity assigned to this app. See relevant docs. " + ManagedIdentityTutorial; public const string SystemAssignedAuthFailure = "The system assigned managed identity for this Function App does not have access to the resource configured in {0}. See relevant docs. " + ManagedIdentityTutorial; public const string UserAssignedAuthFailure = "The configured user assigned managed identity does not have access to the resource configured in {0}. See relevant docs. " + ManagedIdentityTutorial; - // TODO: Update this with relevant documentation link and create resource type specific variants. - public const string AuthFailureDetails = "Authentication failure - the credentials in the configured connection string are either invalid or expired. Please update the app setting with a valid connection string."; + public const string AuthFailureSummary = "Authentication failure. Credentials in connection string configured in app setting {0} are invalid or expired."; + public const string AuthFailureBlobStorageDocs = "See See relevant docs."; + public const string AuthFailureQueueStorageDocs = "See See relevant docs."; + public const string AuthFailureFileShareStorageDocs = "See See relevant docs."; + public const string AuthFailureServiceBusDocs = "See See relevant docs."; + public const string AuthFailureEventHubsDocs = "See See relevant docs."; public const string StorageAccessRestrictedDetails = "This can be due to firewall rules on the resource. Please check if you have configured firewall rules or a private endpoint and that they correctly allow access from the Function App. See Storage account network security for additional details."; public const string ServiceBusAccessRestrictedDetails = "This can be due to firewall rules on the resource. Please check if you have configured firewall rules or a private endpoint and that they correctly allow access from the Function App. See Service Bus network security for additional details."; public const string EventHubAccessRestrictedDetails = "This can be due to firewall rules on the resource. Please check if you have configured firewall rules or a private endpoint and that they correctly allow access from the Function App. See Event Hubs network security for additional details."; diff --git a/DiagnosticsExtension/Models/ConnectionStringValidator/Exceptions/ConnectionStringResponseUtility.cs b/DiagnosticsExtension/Models/ConnectionStringValidator/Exceptions/ConnectionStringResponseUtility.cs index 502e0d2c..0141ab9e 100644 --- a/DiagnosticsExtension/Models/ConnectionStringValidator/Exceptions/ConnectionStringResponseUtility.cs +++ b/DiagnosticsExtension/Models/ConnectionStringValidator/Exceptions/ConnectionStringResponseUtility.cs @@ -35,8 +35,8 @@ public static void EvaluateResponseStatus(Exception e, ConnectionStringType type else if (e is UnauthorizedAccessException && e.Message.Contains("unauthorized") || e.Message.Contains("Unauthorized") || e.Message.Contains("request is not authorized")) { response.Status = ConnectionStringValidationResult.ResultStatus.AuthFailure; - response.StatusSummary = Constants.AuthenticationFailure; - response.StatusDetails = Constants.AuthFailureDetails; + response.StatusSummary = Constants.AuthFailureSummary + " " + GetRelevantAuthFailureDocs(type); + response.StatusDetails = Constants.GenericDetailsMessage; response.Exception = e; } else if (e.InnerException != null && @@ -81,8 +81,8 @@ public static void EvaluateResponseStatus(Exception e, ConnectionStringType type else if (e.Message.Contains("InvalidSignature")) { response.Status = ConnectionStringValidationResult.ResultStatus.AuthFailure; - response.StatusSummary = Constants.AuthenticationFailure; - response.StatusDetails = Constants.AuthFailureDetails; + response.StatusSummary = Constants.AuthFailureSummary + " " + GetRelevantAuthFailureDocs(type); + response.StatusDetails = Constants.GenericDetailsMessage; response.Exception = e; } else if ((e is ArgumentException && e.Message.Contains("Authentication")) || @@ -90,8 +90,8 @@ public static void EvaluateResponseStatus(Exception e, ConnectionStringType type e.Message.Contains("InvalidSignature")) { response.Status = ConnectionStringValidationResult.ResultStatus.AuthFailure; - response.StatusSummary = Constants.AuthenticationFailure; - response.StatusDetails = Constants.AuthFailureDetails; + response.StatusSummary = Constants.AuthFailureSummary + " " + GetRelevantAuthFailureDocs(type); + response.StatusDetails = Constants.GenericDetailsMessage; response.Exception = e; } else if ((e is Azure.RequestFailedException && e.Message.Contains("failed to authenticate")) || @@ -99,8 +99,8 @@ public static void EvaluateResponseStatus(Exception e, ConnectionStringType type e.Message.Contains("InvalidSignature")) { response.Status = ConnectionStringValidationResult.ResultStatus.AuthFailure; - response.StatusSummary = Constants.AuthenticationFailure; - response.StatusDetails = Constants.AuthFailureDetails; + response.StatusSummary = Constants.AuthFailureSummary + " " + GetRelevantAuthFailureDocs(type); + response.StatusDetails = Constants.GenericDetailsMessage; response.Exception = e; } else if (e.Message.Contains("Ip has been prevented to connect to the endpoint")) @@ -108,8 +108,8 @@ public static void EvaluateResponseStatus(Exception e, ConnectionStringType type response.Status = ConnectionStringValidationResult.ResultStatus.Forbidden; if (e.Message.Contains("AuthenticationFailed")) { - response.StatusSummary = Constants.AuthenticationFailure; - response.StatusDetails = Constants.AuthFailureDetails; + response.StatusSummary = Constants.AuthFailureSummary + " " + GetRelevantAuthFailureDocs(type); + response.StatusDetails = Constants.GenericDetailsMessage; } else { @@ -137,16 +137,16 @@ public static void EvaluateResponseStatus(Exception e, ConnectionStringType type if (((StorageException)e).RequestInformation.HttpStatusCode == 401) { response.Status = ConnectionStringValidationResult.ResultStatus.AuthFailure; - response.StatusSummary = Constants.AuthenticationFailure; - response.StatusDetails = Constants.AuthFailureDetails; + response.StatusSummary = Constants.AuthFailureSummary + " " + GetRelevantAuthFailureDocs(type); + response.StatusDetails = Constants.GenericDetailsMessage; } else if (((StorageException)e).RequestInformation.HttpStatusCode == 403) { response.Status = ConnectionStringValidationResult.ResultStatus.Forbidden; if (e.Message.Contains("AuthenticationFailed")) { - response.StatusSummary = Constants.AuthenticationFailure; - response.StatusDetails = Constants.AuthFailureDetails; + response.StatusSummary = Constants.AuthFailureSummary + " " + GetRelevantAuthFailureDocs(type); + response.StatusDetails = Constants.GenericDetailsMessage; } else { @@ -177,5 +177,23 @@ public static void EvaluateResponseStatus(Exception e, ConnectionStringType type } } + private static string GetRelevantAuthFailureDocs(ConnectionStringType type) + { + switch (type) + { + case ConnectionStringType.BlobStorageAccount: + return Constants.AuthFailureBlobStorageDocs; + case ConnectionStringType.QueueStorageAccount: + return Constants.AuthFailureQueueStorageDocs; + case ConnectionStringType.FileShareStorageAccount: + return Constants.AuthFailureFileShareStorageDocs; + case ConnectionStringType.ServiceBus: + return Constants.AuthFailureServiceBusDocs; + case ConnectionStringType.EventHubs: + return Constants.AuthFailureEventHubsDocs; + default: + return ""; + } + } } } From 4ee3cf1872da67fde694f52243eef7658c23fe5b Mon Sep 17 00:00:00 2001 From: Sid Krishna Date: Fri, 8 Apr 2022 03:56:56 -0700 Subject: [PATCH 19/26] Added error handling logic for key vault reference resolution failures and moed two files out of Exceptions folder and namespace --- DiagnosticsExtension/DiagnosticsExtension.csproj | 4 ++-- .../ConnectionStringResponseUtility.cs | 15 +++++++++++++-- .../ConnectionStringValidationResult.cs | 1 + .../Models/ConnectionStringValidator/Constants.cs | 1 + .../ManagedIdentityConnectionResponseUtility.cs | 3 ++- 5 files changed, 19 insertions(+), 5 deletions(-) rename DiagnosticsExtension/Models/ConnectionStringValidator/{Exceptions => }/ConnectionStringResponseUtility.cs (92%) rename DiagnosticsExtension/Models/ConnectionStringValidator/{Exceptions => }/ManagedIdentityConnectionResponseUtility.cs (97%) diff --git a/DiagnosticsExtension/DiagnosticsExtension.csproj b/DiagnosticsExtension/DiagnosticsExtension.csproj index 305da98c..8bcb105f 100644 --- a/DiagnosticsExtension/DiagnosticsExtension.csproj +++ b/DiagnosticsExtension/DiagnosticsExtension.csproj @@ -386,10 +386,10 @@ - + - + diff --git a/DiagnosticsExtension/Models/ConnectionStringValidator/Exceptions/ConnectionStringResponseUtility.cs b/DiagnosticsExtension/Models/ConnectionStringValidator/ConnectionStringResponseUtility.cs similarity index 92% rename from DiagnosticsExtension/Models/ConnectionStringValidator/Exceptions/ConnectionStringResponseUtility.cs rename to DiagnosticsExtension/Models/ConnectionStringValidator/ConnectionStringResponseUtility.cs index 0141ab9e..6fdd5e71 100644 --- a/DiagnosticsExtension/Models/ConnectionStringValidator/Exceptions/ConnectionStringResponseUtility.cs +++ b/DiagnosticsExtension/Models/ConnectionStringValidator/ConnectionStringResponseUtility.cs @@ -12,14 +12,21 @@ using Azure; using Azure.Identity; using Microsoft.WindowsAzure.Storage; +using DiagnosticsExtension.Models.ConnectionStringValidator.Exceptions; -namespace DiagnosticsExtension.Models.ConnectionStringValidator.Exceptions +namespace DiagnosticsExtension.Models.ConnectionStringValidator { public static class ConnectionStringResponseUtility { public static void EvaluateResponseStatus(Exception e, ConnectionStringType type, ref ConnectionStringValidationResult response, string appSettingName = "") { - if (e is MalformedConnectionStringException) + // Check if the value is a key vault reference that failed to resolve to the connection string by platform + if (ConnectionStringResponseUtility.IsKeyVaultReference(Environment.GetEnvironmentVariable(appSettingName))) + { + response.Status = ConnectionStringValidationResult.ResultStatus.KeyVaultReferenceResolutionFailed; + response.StatusSummary = String.Format(Constants.KeyVaultReferenceResolutionFailedSummary, appSettingName); + } + else if (e is MalformedConnectionStringException) { response.Status = ConnectionStringValidationResult.ResultStatus.MalformedConnectionString; response.StatusSummary = String.Format(Constants.MalformedConnectionStringDetails, appSettingName); @@ -176,6 +183,10 @@ public static void EvaluateResponseStatus(Exception e, ConnectionStringType type response.Exception = e; } } + public static bool IsKeyVaultReference(string value) + { + return value.Contains("@Microsoft.KeyVault"); + } private static string GetRelevantAuthFailureDocs(ConnectionStringType type) { diff --git a/DiagnosticsExtension/Models/ConnectionStringValidator/ConnectionStringValidationResult.cs b/DiagnosticsExtension/Models/ConnectionStringValidator/ConnectionStringValidationResult.cs index b6d6600e..c5523cd2 100644 --- a/DiagnosticsExtension/Models/ConnectionStringValidator/ConnectionStringValidationResult.cs +++ b/DiagnosticsExtension/Models/ConnectionStringValidator/ConnectionStringValidationResult.cs @@ -58,6 +58,7 @@ public enum ResultStatus ManagedIdentityNotConfigured, ManagedIdentityAuthFailure, ManagedIdentityConnectionFailed, + KeyVaultReferenceResolutionFailed, UnknownError, } public enum ManagedIdentityCommonProperty diff --git a/DiagnosticsExtension/Models/ConnectionStringValidator/Constants.cs b/DiagnosticsExtension/Models/ConnectionStringValidator/Constants.cs index 05ecddf5..148c911b 100644 --- a/DiagnosticsExtension/Models/ConnectionStringValidator/Constants.cs +++ b/DiagnosticsExtension/Models/ConnectionStringValidator/Constants.cs @@ -55,6 +55,7 @@ public static class Constants public const string StorageAccountResourceNotFound = "The resource specified in the app setting {0} was not found. Please check the value of the setting."; public const string MalformedConnectionStringDetails = "The connection string configured in app setting {0} is invalid (e.g.missing some required elements)."; public const string ManagedIdentityCredentialInvalidSummary = "The app setting {0}" + Credential + " is not valid. To use identity based connections, set it's value to \"managedidentity\". See relevant docs. " + ManagedIdentityTutorial; + public const string KeyVaultReferenceResolutionFailedSummary = "The Azure Key Vault reference configured in app setting {0} could not be resolved. See < a href='https://docs.microsoft.com/azure/app-service/app-service-key-vault-references' target='_blank'>relevant docs to correct the issue."; #endregion } } diff --git a/DiagnosticsExtension/Models/ConnectionStringValidator/Exceptions/ManagedIdentityConnectionResponseUtility.cs b/DiagnosticsExtension/Models/ConnectionStringValidator/ManagedIdentityConnectionResponseUtility.cs similarity index 97% rename from DiagnosticsExtension/Models/ConnectionStringValidator/Exceptions/ManagedIdentityConnectionResponseUtility.cs rename to DiagnosticsExtension/Models/ConnectionStringValidator/ManagedIdentityConnectionResponseUtility.cs index 6176e891..88106d2c 100644 --- a/DiagnosticsExtension/Models/ConnectionStringValidator/Exceptions/ManagedIdentityConnectionResponseUtility.cs +++ b/DiagnosticsExtension/Models/ConnectionStringValidator/ManagedIdentityConnectionResponseUtility.cs @@ -12,8 +12,9 @@ using Azure; using Azure.Identity; using Microsoft.WindowsAzure.Storage; +using DiagnosticsExtension.Models.ConnectionStringValidator.Exceptions; -namespace DiagnosticsExtension.Models.ConnectionStringValidator.Exceptions +namespace DiagnosticsExtension.Models.ConnectionStringValidator { public static class ManagedIdentityConnectionResponseUtility { From aa895f7d740f45666f279812541b7f3187e8dd4f Mon Sep 17 00:00:00 2001 From: Sid Krishna Date: Fri, 8 Apr 2022 04:28:13 -0700 Subject: [PATCH 20/26] Returning a StatusSummary for UnknownError status to keep client side logic simple and compact --- .../ConnectionStringValidator/ConnectionStringResponseUtility.cs | 1 + .../Models/ConnectionStringValidator/Constants.cs | 1 + .../ManagedIdentityConnectionResponseUtility.cs | 1 + 3 files changed, 3 insertions(+) diff --git a/DiagnosticsExtension/Models/ConnectionStringValidator/ConnectionStringResponseUtility.cs b/DiagnosticsExtension/Models/ConnectionStringValidator/ConnectionStringResponseUtility.cs index 6fdd5e71..a65c52ca 100644 --- a/DiagnosticsExtension/Models/ConnectionStringValidator/ConnectionStringResponseUtility.cs +++ b/DiagnosticsExtension/Models/ConnectionStringValidator/ConnectionStringResponseUtility.cs @@ -180,6 +180,7 @@ public static void EvaluateResponseStatus(Exception e, ConnectionStringType type else { response.Status = ConnectionStringValidationResult.ResultStatus.UnknownError; + response.StatusSummary = Constants.UnknownErrorSummary; response.Exception = e; } } diff --git a/DiagnosticsExtension/Models/ConnectionStringValidator/Constants.cs b/DiagnosticsExtension/Models/ConnectionStringValidator/Constants.cs index 148c911b..faaadc53 100644 --- a/DiagnosticsExtension/Models/ConnectionStringValidator/Constants.cs +++ b/DiagnosticsExtension/Models/ConnectionStringValidator/Constants.cs @@ -24,6 +24,7 @@ public static class Constants public const string QueueServiceUri = "__queueServiceUri"; public const string ValidCredentialValue = "managedidentity"; public const string FullyQualifiedNamespace = "__fullyQualifiedNamespace"; + public const string UnknownErrorSummary = "Validation of connection string failed due to an unknown error."; public const string GenericDetailsMessage = "Additional details of the error:"; public const string ManagedIdentityTutorial = "Here is a relevant tutorial."; public const string BlobServiceUriMissingSummary = "Necessary connection settings not found. A connection string or identity-based connection settings are required. See relevant docs. "; diff --git a/DiagnosticsExtension/Models/ConnectionStringValidator/ManagedIdentityConnectionResponseUtility.cs b/DiagnosticsExtension/Models/ConnectionStringValidator/ManagedIdentityConnectionResponseUtility.cs index 88106d2c..5557e4cc 100644 --- a/DiagnosticsExtension/Models/ConnectionStringValidator/ManagedIdentityConnectionResponseUtility.cs +++ b/DiagnosticsExtension/Models/ConnectionStringValidator/ManagedIdentityConnectionResponseUtility.cs @@ -68,6 +68,7 @@ public static void EvaluateResponseStatus(Exception e, ConnectionStringType type else { response.Status = ConnectionStringValidationResult.ResultStatus.UnknownError; + response.StatusSummary = Constants.UnknownErrorSummary; response.Exception = e; } } From 9d880e788283b9e6aeb6f15e30177f79ba38b957 Mon Sep 17 00:00:00 2001 From: Sid Krishna Date: Mon, 18 Apr 2022 19:25:07 -0700 Subject: [PATCH 21/26] Added support for entity not found error handling. Quotes around values in error messages. --- .../ConnectionStringResponseUtility.cs | 5 ++- .../ConnectionStringValidationResult.cs | 1 + .../ConnectionStringValidator/Constants.cs | 36 ++++++++++--------- .../EventHubsValidator.cs | 10 +++++- .../ServiceBusValidator.cs | 10 +++++- 5 files changed, 42 insertions(+), 20 deletions(-) diff --git a/DiagnosticsExtension/Models/ConnectionStringValidator/ConnectionStringResponseUtility.cs b/DiagnosticsExtension/Models/ConnectionStringValidator/ConnectionStringResponseUtility.cs index a65c52ca..20a107a5 100644 --- a/DiagnosticsExtension/Models/ConnectionStringValidator/ConnectionStringResponseUtility.cs +++ b/DiagnosticsExtension/Models/ConnectionStringValidator/ConnectionStringResponseUtility.cs @@ -54,7 +54,7 @@ public static void EvaluateResponseStatus(Exception e, ConnectionStringType type response.Exception = e; } else if (e.InnerException != null && e.InnerException.InnerException != null && - e.InnerException.InnerException.Message.Contains("The remote name could not be resolved")) + e.InnerException.InnerException.Message.Contains("The remote name could not be resolved")) { response.Status = ConnectionStringValidationResult.ResultStatus.DnsLookupFailed; response.StatusSummary = Constants.DnsLookupFailed; @@ -62,6 +62,9 @@ public static void EvaluateResponseStatus(Exception e, ConnectionStringType type } else if (e.Message.Contains("No such host is known")) { + // Thrown when the endpoint specified (e.g. Service Bus namespace) is not found (DNS resolution fails) + // Can happen due to misconfiguration or when the resource cannot be discovered as it is is behind a private + // endpoint not accessible from this network response.Status = ConnectionStringValidationResult.ResultStatus.DnsLookupFailed; response.StatusSummary = Constants.DnsLookupFailed; response.Exception = e; diff --git a/DiagnosticsExtension/Models/ConnectionStringValidator/ConnectionStringValidationResult.cs b/DiagnosticsExtension/Models/ConnectionStringValidator/ConnectionStringValidationResult.cs index c5523cd2..d0f27ec9 100644 --- a/DiagnosticsExtension/Models/ConnectionStringValidator/ConnectionStringValidationResult.cs +++ b/DiagnosticsExtension/Models/ConnectionStringValidator/ConnectionStringValidationResult.cs @@ -54,6 +54,7 @@ public enum ResultStatus MsiFailure, EmptyConnectionString, MalformedConnectionString, + EntityNotFound, FullyQualifiedNamespaceMissing, ManagedIdentityNotConfigured, ManagedIdentityAuthFailure, diff --git a/DiagnosticsExtension/Models/ConnectionStringValidator/Constants.cs b/DiagnosticsExtension/Models/ConnectionStringValidator/Constants.cs index faaadc53..60f65d14 100644 --- a/DiagnosticsExtension/Models/ConnectionStringValidator/Constants.cs +++ b/DiagnosticsExtension/Models/ConnectionStringValidator/Constants.cs @@ -14,7 +14,6 @@ namespace DiagnosticsExtension.Models.ConnectionStringValidator { public static class Constants { - #region string constants for network validator public const string User = "User"; public const string System = "System"; public const string UnderscoreSeperator = "__"; @@ -31,18 +30,18 @@ public static class Constants public const string QueueServiceUriMissingSummary = "Necessary connection settings not found. A connection string or identity-based connection settings are required. See relevant docs. "; public const string ServiceBusFQMissingSummary = "Necessary connection settings not found. A connection string or identity-based connection settings are required. See relevant docs. "; public const string EventHubFQMissingSummary = "Necessary connection settings not found. A connection string or identity-based connection settings are required. See relevant docs. "; - public const string BlobServiceUriEmptySummary = "The app setting {0} has no value. See relevant docs. " + ManagedIdentityTutorial; - public const string QueueServiceUriEmptySummary = "The app setting {0} has no value. See relevant docs. " + ManagedIdentityTutorial; - public const string ServiceBusFQNSEmptySummary = "The app setting {0} has no value. See relevant docs. " + ManagedIdentityTutorial; - public const string EventHubFQNSEmptySummary = "The app setting {0} has no value. See relevant docs. " + ManagedIdentityTutorial; - public const string ManagedIdentityClientIdEmptySummary = "The app setting {0} has no value."; - public const string ManagedIdentityClientIdEmptyDetails = "When the app setting {0}" + Credential + " is configured to \"managedidentity\", the clientId of a user assigned managed identity assigned to the Function App is expected in the app setting {0}" + ClientId + ". See relevant docs. " + ManagedIdentityTutorial; + public const string BlobServiceUriEmptySummary = "The app setting '{0}' has no value. See relevant docs. " + ManagedIdentityTutorial; + public const string QueueServiceUriEmptySummary = "The app setting '{0}' has no value. See relevant docs. " + ManagedIdentityTutorial; + public const string ServiceBusFQNSEmptySummary = "The app setting '{0}' has no value. See relevant docs. " + ManagedIdentityTutorial; + public const string EventHubFQNSEmptySummary = "The app setting '{0}' has no value. See relevant docs. " + ManagedIdentityTutorial; + public const string ManagedIdentityClientIdEmptySummary = "The app setting '{0}' has no value."; + public const string ManagedIdentityClientIdEmptyDetails = "When the app setting '{0}'" + Credential + " is configured to \"managedidentity\", the clientId of a user assigned managed identity assigned to the Function App is expected in the app setting {0}" + ClientId + ". See relevant docs. " + ManagedIdentityTutorial; public const string AuthorizationFailure = "Authorization failure"; public const string AuthenticationFailure = "Authentication failure"; - public const string ClientIdInvalidTokenGeneratedSummary = "The value of app setting {0}" + ClientId + " does not match any user assigned managed identity assigned to this app. See relevant docs. " + ManagedIdentityTutorial; - public const string SystemAssignedAuthFailure = "The system assigned managed identity for this Function App does not have access to the resource configured in {0}. See relevant docs. " + ManagedIdentityTutorial; - public const string UserAssignedAuthFailure = "The configured user assigned managed identity does not have access to the resource configured in {0}. See relevant docs. " + ManagedIdentityTutorial; - public const string AuthFailureSummary = "Authentication failure. Credentials in connection string configured in app setting {0} are invalid or expired."; + public const string ClientIdInvalidTokenGeneratedSummary = "The value of app setting '{0}'" + ClientId + " does not match any user assigned managed identity assigned to this app. See relevant docs. " + ManagedIdentityTutorial; + public const string SystemAssignedAuthFailure = "The system assigned managed identity for this Function App does not have access to the resource configured in '{0}'. See relevant docs. " + ManagedIdentityTutorial; + public const string UserAssignedAuthFailure = "The configured user assigned managed identity does not have access to the resource configured in '{0}'. See relevant docs. " + ManagedIdentityTutorial; + public const string AuthFailureSummary = "Authentication failure. Credentials in connection string configured in app setting '{0}' are invalid or expired."; public const string AuthFailureBlobStorageDocs = "See See relevant docs."; public const string AuthFailureQueueStorageDocs = "See See relevant docs."; public const string AuthFailureFileShareStorageDocs = "See See relevant docs."; @@ -52,11 +51,14 @@ public static class Constants public const string ServiceBusAccessRestrictedDetails = "This can be due to firewall rules on the resource. Please check if you have configured firewall rules or a private endpoint and that they correctly allow access from the Function App. See Service Bus network security for additional details."; public const string EventHubAccessRestrictedDetails = "This can be due to firewall rules on the resource. Please check if you have configured firewall rules or a private endpoint and that they correctly allow access from the Function App. See Event Hubs network security for additional details."; public const string DnsLookupFailed = "The service resource specified in the connection string was not found. Please check the value of the setting."; - public const string FQNamespaceResourceNotFound = "The resource specified in the app setting {0}" + FullyQualifiedNamespace + " was not found. Please check the value of the setting."; - public const string StorageAccountResourceNotFound = "The resource specified in the app setting {0} was not found. Please check the value of the setting."; - public const string MalformedConnectionStringDetails = "The connection string configured in app setting {0} is invalid (e.g.missing some required elements)."; - public const string ManagedIdentityCredentialInvalidSummary = "The app setting {0}" + Credential + " is not valid. To use identity based connections, set it's value to \"managedidentity\". See relevant docs. " + ManagedIdentityTutorial; - public const string KeyVaultReferenceResolutionFailedSummary = "The Azure Key Vault reference configured in app setting {0} could not be resolved. See < a href='https://docs.microsoft.com/azure/app-service/app-service-key-vault-references' target='_blank'>relevant docs to correct the issue."; - #endregion + public const string FQNamespaceResourceNotFound = "The resource specified in the app setting '{0}" + FullyQualifiedNamespace + "' was not found. Please check the value of the setting."; + public const string StorageAccountResourceNotFound = "The resource specified in the app setting '{0}' was not found. Please check the value of the setting."; + public const string MalformedConnectionStringDetails = "The connection string configured in app setting '{0}' is invalid (e.g.missing some required elements)."; + public const string EventHubEntityNotFoundSummary = "The configured Event Hub '{0}' was not found."; + public const string EventHubEntityNotFoundDetails = "Refer to relevant docs and check the value of the attribute 'EventHubName' in your code."; + public const string ServiceBusEntityNotFoundSummary = "The configured Queue or Topic '{0}' was not found."; + public const string ServiceBusEntityNotFoundDetails = "Refer to relevant docs and check the value of the attribute 'QueueName' or 'TopicName' in your code."; + public const string ManagedIdentityCredentialInvalidSummary = "The app setting '{0}" + Credential + "' is not valid. To use identity based connections, set it's value to \"managedidentity\". See relevant docs. " + ManagedIdentityTutorial; + public const string KeyVaultReferenceResolutionFailedSummary = "The Azure Key Vault reference configured in app setting '{0}' could not be resolved. See < a href='https://docs.microsoft.com/azure/app-service/app-service-key-vault-references' target='_blank'>relevant docs to correct the issue."; } } diff --git a/DiagnosticsExtension/Models/ConnectionStringValidator/EventHubsValidator.cs b/DiagnosticsExtension/Models/ConnectionStringValidator/EventHubsValidator.cs index 5fc7e652..e888ed97 100644 --- a/DiagnosticsExtension/Models/ConnectionStringValidator/EventHubsValidator.cs +++ b/DiagnosticsExtension/Models/ConnectionStringValidator/EventHubsValidator.cs @@ -153,7 +153,15 @@ async public Task ValidateViaAppsettingAsync(s } catch (Exception e) { - if (isManagedIdentityConnection) + // TODO: Find out what exception class is thrown for the message below and add that to the set of conditions + if (e.Message.Contains("The messaging entity") && e.Message.Contains("could not be found")) + { + response.Status = ConnectionStringValidationResult.ResultStatus.EntityNotFound; + response.StatusSummary = String.Format(Constants.EventHubEntityNotFoundSummary, entityName); + response.StatusDetails = Constants.EventHubEntityNotFoundDetails; + response.Exception = e; + } + else if (isManagedIdentityConnection) { ManagedIdentityConnectionResponseUtility.EvaluateResponseStatus(e, Type, ref response, appSettingName); } diff --git a/DiagnosticsExtension/Models/ConnectionStringValidator/ServiceBusValidator.cs b/DiagnosticsExtension/Models/ConnectionStringValidator/ServiceBusValidator.cs index 90c0cf18..ea80138b 100644 --- a/DiagnosticsExtension/Models/ConnectionStringValidator/ServiceBusValidator.cs +++ b/DiagnosticsExtension/Models/ConnectionStringValidator/ServiceBusValidator.cs @@ -169,7 +169,15 @@ async public Task ValidateViaAppsettingAsync(s } catch (Exception e) { - if (isManagedIdentityConnection) + // TODO: Find out what exception class is thrown for the message below and add that to the set of conditions + if (e.Message.Contains("The messaging entity") && e.Message.Contains("could not be found")) + { + response.Status = ConnectionStringValidationResult.ResultStatus.EntityNotFound; + response.StatusSummary = String.Format(Constants.ServiceBusEntityNotFoundSummary, entityName); + response.StatusDetails = Constants.ServiceBusEntityNotFoundDetails; + response.Exception = e; + } + else if (isManagedIdentityConnection) { ManagedIdentityConnectionResponseUtility.EvaluateResponseStatus(e, Type, ref response, appSettingName); } From ef2aa5444f84eee7c72ba252762bb61588d99092 Mon Sep 17 00:00:00 2001 From: Gajibilli Koteswara Rao Date: Tue, 19 Apr 2022 10:24:15 +0530 Subject: [PATCH 22/26] Code changes as per the comments --- .../ConnectionStringResponseUtility.cs | 14 ++--- .../ConnectionStringValidator/Constants.cs | 2 +- .../FileShareStorageValidator.cs | 56 ++++++------------- 3 files changed, 26 insertions(+), 46 deletions(-) diff --git a/DiagnosticsExtension/Models/ConnectionStringValidator/ConnectionStringResponseUtility.cs b/DiagnosticsExtension/Models/ConnectionStringValidator/ConnectionStringResponseUtility.cs index a65c52ca..fae8625e 100644 --- a/DiagnosticsExtension/Models/ConnectionStringValidator/ConnectionStringResponseUtility.cs +++ b/DiagnosticsExtension/Models/ConnectionStringValidator/ConnectionStringResponseUtility.cs @@ -42,7 +42,7 @@ public static void EvaluateResponseStatus(Exception e, ConnectionStringType type else if (e is UnauthorizedAccessException && e.Message.Contains("unauthorized") || e.Message.Contains("Unauthorized") || e.Message.Contains("request is not authorized")) { response.Status = ConnectionStringValidationResult.ResultStatus.AuthFailure; - response.StatusSummary = Constants.AuthFailureSummary + " " + GetRelevantAuthFailureDocs(type); + response.StatusSummary = String.Format(Constants.AuthFailureSummary, appSettingName) + " " + GetRelevantAuthFailureDocs(type); response.StatusDetails = Constants.GenericDetailsMessage; response.Exception = e; } @@ -88,7 +88,7 @@ public static void EvaluateResponseStatus(Exception e, ConnectionStringType type else if (e.Message.Contains("InvalidSignature")) { response.Status = ConnectionStringValidationResult.ResultStatus.AuthFailure; - response.StatusSummary = Constants.AuthFailureSummary + " " + GetRelevantAuthFailureDocs(type); + response.StatusSummary = String.Format(Constants.AuthFailureSummary, appSettingName) + " " + GetRelevantAuthFailureDocs(type); response.StatusDetails = Constants.GenericDetailsMessage; response.Exception = e; } @@ -97,7 +97,7 @@ public static void EvaluateResponseStatus(Exception e, ConnectionStringType type e.Message.Contains("InvalidSignature")) { response.Status = ConnectionStringValidationResult.ResultStatus.AuthFailure; - response.StatusSummary = Constants.AuthFailureSummary + " " + GetRelevantAuthFailureDocs(type); + response.StatusSummary = String.Format(Constants.AuthFailureSummary, appSettingName) + " " + GetRelevantAuthFailureDocs(type); response.StatusDetails = Constants.GenericDetailsMessage; response.Exception = e; } @@ -106,7 +106,7 @@ public static void EvaluateResponseStatus(Exception e, ConnectionStringType type e.Message.Contains("InvalidSignature")) { response.Status = ConnectionStringValidationResult.ResultStatus.AuthFailure; - response.StatusSummary = Constants.AuthFailureSummary + " " + GetRelevantAuthFailureDocs(type); + response.StatusSummary = String.Format(Constants.AuthFailureSummary, appSettingName) + " " + GetRelevantAuthFailureDocs(type); response.StatusDetails = Constants.GenericDetailsMessage; response.Exception = e; } @@ -115,7 +115,7 @@ public static void EvaluateResponseStatus(Exception e, ConnectionStringType type response.Status = ConnectionStringValidationResult.ResultStatus.Forbidden; if (e.Message.Contains("AuthenticationFailed")) { - response.StatusSummary = Constants.AuthFailureSummary + " " + GetRelevantAuthFailureDocs(type); + response.StatusSummary = String.Format(Constants.AuthFailureSummary, appSettingName) + " " + GetRelevantAuthFailureDocs(type); response.StatusDetails = Constants.GenericDetailsMessage; } else @@ -144,7 +144,7 @@ public static void EvaluateResponseStatus(Exception e, ConnectionStringType type if (((StorageException)e).RequestInformation.HttpStatusCode == 401) { response.Status = ConnectionStringValidationResult.ResultStatus.AuthFailure; - response.StatusSummary = Constants.AuthFailureSummary + " " + GetRelevantAuthFailureDocs(type); + response.StatusSummary = String.Format(Constants.AuthFailureSummary, appSettingName) + " " + GetRelevantAuthFailureDocs(type); response.StatusDetails = Constants.GenericDetailsMessage; } else if (((StorageException)e).RequestInformation.HttpStatusCode == 403) @@ -152,7 +152,7 @@ public static void EvaluateResponseStatus(Exception e, ConnectionStringType type response.Status = ConnectionStringValidationResult.ResultStatus.Forbidden; if (e.Message.Contains("AuthenticationFailed")) { - response.StatusSummary = Constants.AuthFailureSummary + " " + GetRelevantAuthFailureDocs(type); + response.StatusSummary = String.Format(Constants.AuthFailureSummary, appSettingName) + " " + GetRelevantAuthFailureDocs(type); response.StatusDetails = Constants.GenericDetailsMessage; } else diff --git a/DiagnosticsExtension/Models/ConnectionStringValidator/Constants.cs b/DiagnosticsExtension/Models/ConnectionStringValidator/Constants.cs index faaadc53..a1a738ee 100644 --- a/DiagnosticsExtension/Models/ConnectionStringValidator/Constants.cs +++ b/DiagnosticsExtension/Models/ConnectionStringValidator/Constants.cs @@ -56,7 +56,7 @@ public static class Constants public const string StorageAccountResourceNotFound = "The resource specified in the app setting {0} was not found. Please check the value of the setting."; public const string MalformedConnectionStringDetails = "The connection string configured in app setting {0} is invalid (e.g.missing some required elements)."; public const string ManagedIdentityCredentialInvalidSummary = "The app setting {0}" + Credential + " is not valid. To use identity based connections, set it's value to \"managedidentity\". See relevant docs. " + ManagedIdentityTutorial; - public const string KeyVaultReferenceResolutionFailedSummary = "The Azure Key Vault reference configured in app setting {0} could not be resolved. See < a href='https://docs.microsoft.com/azure/app-service/app-service-key-vault-references' target='_blank'>relevant docs to correct the issue."; + public const string KeyVaultReferenceResolutionFailedSummary = "The Azure Key Vault reference configured in app setting {0} could not be resolved. See relevant docs to correct the issue."; #endregion } } diff --git a/DiagnosticsExtension/Models/ConnectionStringValidator/FileShareStorageValidator.cs b/DiagnosticsExtension/Models/ConnectionStringValidator/FileShareStorageValidator.cs index 1151d8c2..0c4780f8 100644 --- a/DiagnosticsExtension/Models/ConnectionStringValidator/FileShareStorageValidator.cs +++ b/DiagnosticsExtension/Models/ConnectionStringValidator/FileShareStorageValidator.cs @@ -23,58 +23,38 @@ public class FileShareStorageValidator : IConnectionStringValidator { public string ProviderName => "Microsoft.WindowsAzure.Storage"; public ConnectionStringType Type => ConnectionStringType.FileShareStorageAccount; - public async Task ValidateViaAppsettingAsync(string appsettingname, string entityName) + public async Task ValidateViaAppsettingAsync(string appSettingName, string entityName) { - var response = new ConnectionStringValidationResult(Type); - + ConnectionStringValidationResult response = new ConnectionStringValidationResult(Type); try { - var result = await TestConnectionStringViaAppSettingAsync(appsettingname, entityName); - if (result.Succeeded) + var envDict = Environment.GetEnvironmentVariables(); + ShareServiceClient client = null; + try { - response.Status = ConnectionStringValidationResult.ResultStatus.Success; + if (envDict.Contains(appSettingName)) + { + string connectionString = Environment.GetEnvironmentVariable(appSettingName); + client = new ShareServiceClient(connectionString); + } } - else + catch (ArgumentNullException e) { - throw new Exception("Unexpected state reached: result.Succeeded == false is unexpected!"); + throw new EmptyConnectionStringException(e.Message, e); } - } - catch (Exception e) - { - ConnectionStringResponseUtility.EvaluateResponseStatus(e, Type, ref response); - } - - return response; - } - - public async Task TestConnectionStringViaAppSettingAsync(string appSettingName, string entityName) - { - string value = ""; - var envDict = Environment.GetEnvironmentVariables(); - ShareServiceClient client = null; - try - { - if (envDict.Contains(appSettingName)) + catch (Exception e) { - value = Environment.GetEnvironmentVariable(appSettingName); - client = new ShareServiceClient(value); + throw new MalformedConnectionStringException(e.Message, e); } client.GetSharesAsync(); - } - catch (ArgumentNullException e) - { - throw new EmptyConnectionStringException(e.Message, e); + response.Status = ConnectionStringValidationResult.ResultStatus.Success; } catch (Exception e) { - throw new MalformedConnectionStringException(e.Message, e); + ConnectionStringResponseUtility.EvaluateResponseStatus(e, Type, ref response, appSettingName); } - TestConnectionData data = new TestConnectionData - { - ConnectionString = client.ToString(), - Succeeded = true - }; - return data; + + return response; } public async Task ValidateAsync(string connStr, string clientId = null) { From e997f661314b03b0e37446d9a6c45857588829fe Mon Sep 17 00:00:00 2001 From: Gajibilli Koteswara Rao Date: Mon, 25 Apr 2022 22:00:13 +0530 Subject: [PATCH 23/26] Code changes as per the latest comments. --- .../ConnectionStringValidationResult.cs | 2 +- .../Models/ConnectionStringValidator/Constants.cs | 6 +++--- .../Models/ConnectionStringValidator/ServiceBusValidator.cs | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/DiagnosticsExtension/Models/ConnectionStringValidator/ConnectionStringValidationResult.cs b/DiagnosticsExtension/Models/ConnectionStringValidator/ConnectionStringValidationResult.cs index d0f27ec9..a1a2db50 100644 --- a/DiagnosticsExtension/Models/ConnectionStringValidator/ConnectionStringValidationResult.cs +++ b/DiagnosticsExtension/Models/ConnectionStringValidator/ConnectionStringValidationResult.cs @@ -27,7 +27,7 @@ public class ConnectionStringValidationResult [JsonProperty("Details")] public string StatusDetails; public string StatusText => Status?.ToString(); - [Newtonsoft.Json.JsonIgnore] + public Exception Exception; public string ExceptionMessage => Exception?.Message; [Newtonsoft.Json.JsonIgnore] diff --git a/DiagnosticsExtension/Models/ConnectionStringValidator/Constants.cs b/DiagnosticsExtension/Models/ConnectionStringValidator/Constants.cs index 60f65d14..b71af0e0 100644 --- a/DiagnosticsExtension/Models/ConnectionStringValidator/Constants.cs +++ b/DiagnosticsExtension/Models/ConnectionStringValidator/Constants.cs @@ -55,10 +55,10 @@ public static class Constants public const string StorageAccountResourceNotFound = "The resource specified in the app setting '{0}' was not found. Please check the value of the setting."; public const string MalformedConnectionStringDetails = "The connection string configured in app setting '{0}' is invalid (e.g.missing some required elements)."; public const string EventHubEntityNotFoundSummary = "The configured Event Hub '{0}' was not found."; - public const string EventHubEntityNotFoundDetails = "Refer to relevant docs and check the value of the attribute 'EventHubName' in your code."; + public const string EventHubEntityNotFoundDetails = "Refer to relevant docs and check the value of the attribute 'EventHubName' in your code."; public const string ServiceBusEntityNotFoundSummary = "The configured Queue or Topic '{0}' was not found."; - public const string ServiceBusEntityNotFoundDetails = "Refer to relevant docs and check the value of the attribute 'QueueName' or 'TopicName' in your code."; + public const string ServiceBusEntityNotFoundDetails = "Refer to relevant docs and check the value of the attribute 'QueueName' or 'TopicName' in your code."; public const string ManagedIdentityCredentialInvalidSummary = "The app setting '{0}" + Credential + "' is not valid. To use identity based connections, set it's value to \"managedidentity\". See relevant docs. " + ManagedIdentityTutorial; - public const string KeyVaultReferenceResolutionFailedSummary = "The Azure Key Vault reference configured in app setting '{0}' could not be resolved. See < a href='https://docs.microsoft.com/azure/app-service/app-service-key-vault-references' target='_blank'>relevant docs to correct the issue."; + public const string KeyVaultReferenceResolutionFailedSummary = "The Azure Key Vault reference configured in app setting '{0}' could not be resolved. See relevant docs to correct the issue."; } } diff --git a/DiagnosticsExtension/Models/ConnectionStringValidator/ServiceBusValidator.cs b/DiagnosticsExtension/Models/ConnectionStringValidator/ServiceBusValidator.cs index ea80138b..c4c78259 100644 --- a/DiagnosticsExtension/Models/ConnectionStringValidator/ServiceBusValidator.cs +++ b/DiagnosticsExtension/Models/ConnectionStringValidator/ServiceBusValidator.cs @@ -170,7 +170,7 @@ async public Task ValidateViaAppsettingAsync(s catch (Exception e) { // TODO: Find out what exception class is thrown for the message below and add that to the set of conditions - if (e.Message.Contains("The messaging entity") && e.Message.Contains("could not be found")) + if (e.Message.Contains("Put token failed") && e.Message.Contains("could not be found")) { response.Status = ConnectionStringValidationResult.ResultStatus.EntityNotFound; response.StatusSummary = String.Format(Constants.ServiceBusEntityNotFoundSummary, entityName); From 474051a93f76c3407778d59e748e2c3ff7f0ab11 Mon Sep 17 00:00:00 2001 From: Sid Krishna Date: Tue, 26 Apr 2022 21:29:57 -0700 Subject: [PATCH 24/26] PR feedback on messaging. --- .../ConnectionStringValidator/Constants.cs | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/DiagnosticsExtension/Models/ConnectionStringValidator/Constants.cs b/DiagnosticsExtension/Models/ConnectionStringValidator/Constants.cs index b71af0e0..37b3c701 100644 --- a/DiagnosticsExtension/Models/ConnectionStringValidator/Constants.cs +++ b/DiagnosticsExtension/Models/ConnectionStringValidator/Constants.cs @@ -24,8 +24,8 @@ public static class Constants public const string ValidCredentialValue = "managedidentity"; public const string FullyQualifiedNamespace = "__fullyQualifiedNamespace"; public const string UnknownErrorSummary = "Validation of connection string failed due to an unknown error."; - public const string GenericDetailsMessage = "Additional details of the error:"; - public const string ManagedIdentityTutorial = "Here is a relevant tutorial."; + public const string GenericDetailsMessage = "Additional error details:"; + public const string ManagedIdentityTutorial = "Refer to this relevant tutorial."; public const string BlobServiceUriMissingSummary = "Necessary connection settings not found. A connection string or identity-based connection settings are required. See relevant docs. "; public const string QueueServiceUriMissingSummary = "Necessary connection settings not found. A connection string or identity-based connection settings are required. See relevant docs. "; public const string ServiceBusFQMissingSummary = "Necessary connection settings not found. A connection string or identity-based connection settings are required. See relevant docs. "; @@ -38,27 +38,27 @@ public static class Constants public const string ManagedIdentityClientIdEmptyDetails = "When the app setting '{0}'" + Credential + " is configured to \"managedidentity\", the clientId of a user assigned managed identity assigned to the Function App is expected in the app setting {0}" + ClientId + ". See relevant docs. " + ManagedIdentityTutorial; public const string AuthorizationFailure = "Authorization failure"; public const string AuthenticationFailure = "Authentication failure"; - public const string ClientIdInvalidTokenGeneratedSummary = "The value of app setting '{0}'" + ClientId + " does not match any user assigned managed identity assigned to this app. See relevant docs. " + ManagedIdentityTutorial; + public const string ClientIdInvalidTokenGeneratedSummary = "The value of the app setting '{0}'" + ClientId + " does not match any user assigned managed identity assigned to this app. See relevant docs. " + ManagedIdentityTutorial; public const string SystemAssignedAuthFailure = "The system assigned managed identity for this Function App does not have access to the resource configured in '{0}'. See relevant docs. " + ManagedIdentityTutorial; public const string UserAssignedAuthFailure = "The configured user assigned managed identity does not have access to the resource configured in '{0}'. See relevant docs. " + ManagedIdentityTutorial; public const string AuthFailureSummary = "Authentication failure. Credentials in connection string configured in app setting '{0}' are invalid or expired."; - public const string AuthFailureBlobStorageDocs = "See See relevant docs."; - public const string AuthFailureQueueStorageDocs = "See See relevant docs."; - public const string AuthFailureFileShareStorageDocs = "See See relevant docs."; - public const string AuthFailureServiceBusDocs = "See See relevant docs."; - public const string AuthFailureEventHubsDocs = "See See relevant docs."; - public const string StorageAccessRestrictedDetails = "This can be due to firewall rules on the resource. Please check if you have configured firewall rules or a private endpoint and that they correctly allow access from the Function App. See Storage account network security for additional details."; - public const string ServiceBusAccessRestrictedDetails = "This can be due to firewall rules on the resource. Please check if you have configured firewall rules or a private endpoint and that they correctly allow access from the Function App. See Service Bus network security for additional details."; - public const string EventHubAccessRestrictedDetails = "This can be due to firewall rules on the resource. Please check if you have configured firewall rules or a private endpoint and that they correctly allow access from the Function App. See Event Hubs network security for additional details."; + public const string AuthFailureBlobStorageDocs = "See relevant docs."; + public const string AuthFailureQueueStorageDocs = "See relevant docs."; + public const string AuthFailureFileShareStorageDocs = "See relevant docs."; + public const string AuthFailureServiceBusDocs = "See relevant docs."; + public const string AuthFailureEventHubsDocs = "See relevant docs."; + public const string StorageAccessRestrictedDetails = "This may be due to firewall rules on the resource. Please check if you have configured firewall rules or a private endpoint and that they correctly allow access from the Function App. See Storage account network security for additional details."; + public const string ServiceBusAccessRestrictedDetails = "This may be due to firewall rules on the resource. Please check if you have configured firewall rules or a private endpoint and that they correctly allow access from the Function App. See Service Bus network security for additional details."; + public const string EventHubAccessRestrictedDetails = "This may be due to firewall rules on the resource. Please check if you have configured firewall rules or a private endpoint and that they correctly allow access from the Function App. See Event Hubs network security for additional details."; public const string DnsLookupFailed = "The service resource specified in the connection string was not found. Please check the value of the setting."; public const string FQNamespaceResourceNotFound = "The resource specified in the app setting '{0}" + FullyQualifiedNamespace + "' was not found. Please check the value of the setting."; public const string StorageAccountResourceNotFound = "The resource specified in the app setting '{0}' was not found. Please check the value of the setting."; - public const string MalformedConnectionStringDetails = "The connection string configured in app setting '{0}' is invalid (e.g.missing some required elements)."; + public const string MalformedConnectionStringDetails = "The connection string configured in app setting '{0}' is invalid. Please check the value of the setting."; public const string EventHubEntityNotFoundSummary = "The configured Event Hub '{0}' was not found."; public const string EventHubEntityNotFoundDetails = "Refer to relevant docs and check the value of the attribute 'EventHubName' in your code."; public const string ServiceBusEntityNotFoundSummary = "The configured Queue or Topic '{0}' was not found."; public const string ServiceBusEntityNotFoundDetails = "Refer to relevant docs and check the value of the attribute 'QueueName' or 'TopicName' in your code."; - public const string ManagedIdentityCredentialInvalidSummary = "The app setting '{0}" + Credential + "' is not valid. To use identity based connections, set it's value to \"managedidentity\". See relevant docs. " + ManagedIdentityTutorial; - public const string KeyVaultReferenceResolutionFailedSummary = "The Azure Key Vault reference configured in app setting '{0}' could not be resolved. See relevant docs to correct the issue."; + public const string ManagedIdentityCredentialInvalidSummary = "The app setting '{0}" + Credential + "' is not valid. To use identity-based connections, set its value to \"managedidentity\". See relevant docs. " + ManagedIdentityTutorial; + public const string KeyVaultReferenceResolutionFailedSummary = "The Azure Key Vault reference configured in app setting '{0}' could not be resolved. See relevant docs."; } } From 54fccf6e60c9c453d4af53b2d8a2ccecafd8aa4e Mon Sep 17 00:00:00 2001 From: Gajibilli Koteswara Rao Date: Fri, 13 May 2022 22:58:15 +0530 Subject: [PATCH 25/26] Modified the code as per the comments by yifguoMSFT --- .../ConnectionStringValidationController.cs | 11 ++- .../DiagnosticsExtension.csproj | 2 +- .../ConnectionStringResponseUtility.cs | 68 +++++++++---------- .../ConnectionStringValidationResult.cs | 7 +- .../EventHubsValidator.cs | 4 +- ...anagedIdentityConnectionResponseUtility.cs | 22 +++--- .../ServiceBusValidator.cs | 4 +- 7 files changed, 61 insertions(+), 57 deletions(-) diff --git a/DiagnosticsExtension/Controllers/ConnectionStringValidationController.cs b/DiagnosticsExtension/Controllers/ConnectionStringValidationController.cs index 0f00a089..69aae284 100644 --- a/DiagnosticsExtension/Controllers/ConnectionStringValidationController.cs +++ b/DiagnosticsExtension/Controllers/ConnectionStringValidationController.cs @@ -79,9 +79,16 @@ public async Task Validate([FromBody] ConnectionStringReque return result; } + /// + /// This method is used to validate connection information via appsetting. + /// + /// This should be the configured appsetting key/connection property of the function. + /// This should be the type of Azure service being connected. + /// This is valid only for servicebus and eventhub. Need not be passed for other azure services. + /// ConnectionStringValidationResult [HttpGet] - [Route("validateappsetting")] - public async Task ValidateAppSetting(string appSettingName, string type, string entityName = null) + [Route("validateappsettingforfunctionapp")] + public async Task ValidateAppSettingForFunctionApp(string appSettingName, string type, string entityName = null) { bool success = Enum.TryParse(type, out ConnectionStringType csType); if (success && typeValidatorMap.ContainsKey(csType)) diff --git a/DiagnosticsExtension/DiagnosticsExtension.csproj b/DiagnosticsExtension/DiagnosticsExtension.csproj index 8bcb105f..0b193945 100644 --- a/DiagnosticsExtension/DiagnosticsExtension.csproj +++ b/DiagnosticsExtension/DiagnosticsExtension.csproj @@ -400,9 +400,9 @@ - + diff --git a/DiagnosticsExtension/Models/ConnectionStringValidator/ConnectionStringResponseUtility.cs b/DiagnosticsExtension/Models/ConnectionStringValidator/ConnectionStringResponseUtility.cs index ed2e1adf..6bf4914f 100644 --- a/DiagnosticsExtension/Models/ConnectionStringValidator/ConnectionStringResponseUtility.cs +++ b/DiagnosticsExtension/Models/ConnectionStringValidator/ConnectionStringResponseUtility.cs @@ -24,40 +24,40 @@ public static void EvaluateResponseStatus(Exception e, ConnectionStringType type if (ConnectionStringResponseUtility.IsKeyVaultReference(Environment.GetEnvironmentVariable(appSettingName))) { response.Status = ConnectionStringValidationResult.ResultStatus.KeyVaultReferenceResolutionFailed; - response.StatusSummary = String.Format(Constants.KeyVaultReferenceResolutionFailedSummary, appSettingName); + response.Summary = String.Format(Constants.KeyVaultReferenceResolutionFailedSummary, appSettingName); } else if (e is MalformedConnectionStringException) { response.Status = ConnectionStringValidationResult.ResultStatus.MalformedConnectionString; - response.StatusSummary = String.Format(Constants.MalformedConnectionStringDetails, appSettingName); - response.StatusDetails = Constants.GenericDetailsMessage; + response.Summary = String.Format(Constants.MalformedConnectionStringDetails, appSettingName); + response.Details = Constants.GenericDetailsMessage; response.Exception = e; } else if (e is EmptyConnectionStringException) { response.Status = ConnectionStringValidationResult.ResultStatus.EmptyConnectionString; - response.StatusSummary = "The app setting " + appSettingName + " was not found or is set to a blank value"; + response.Summary = "The app setting " + appSettingName + " was not found or is set to a blank value"; response.Exception = e; } else if (e is UnauthorizedAccessException && e.Message.Contains("unauthorized") || e.Message.Contains("Unauthorized") || e.Message.Contains("request is not authorized")) { response.Status = ConnectionStringValidationResult.ResultStatus.AuthFailure; - response.StatusSummary = String.Format(Constants.AuthFailureSummary, appSettingName) + " " + GetRelevantAuthFailureDocs(type); - response.StatusDetails = Constants.GenericDetailsMessage; + response.Summary = String.Format(Constants.AuthFailureSummary, appSettingName) + " " + GetRelevantAuthFailureDocs(type); + response.Details = Constants.GenericDetailsMessage; response.Exception = e; } else if (e.InnerException != null && e.InnerException.Message.Contains("The remote name could not be resolved")) { response.Status = ConnectionStringValidationResult.ResultStatus.DnsLookupFailed; - response.StatusSummary = Constants.DnsLookupFailed; + response.Summary = Constants.DnsLookupFailed; response.Exception = e; } else if (e.InnerException != null && e.InnerException.InnerException != null && e.InnerException.InnerException.Message.Contains("The remote name could not be resolved")) { response.Status = ConnectionStringValidationResult.ResultStatus.DnsLookupFailed; - response.StatusSummary = Constants.DnsLookupFailed; + response.Summary = Constants.DnsLookupFailed; response.Exception = e; } else if (e.Message.Contains("No such host is known")) @@ -66,7 +66,7 @@ public static void EvaluateResponseStatus(Exception e, ConnectionStringType type // Can happen due to misconfiguration or when the resource cannot be discovered as it is is behind a private // endpoint not accessible from this network response.Status = ConnectionStringValidationResult.ResultStatus.DnsLookupFailed; - response.StatusSummary = Constants.DnsLookupFailed; + response.Summary = Constants.DnsLookupFailed; response.Exception = e; } else if (e is ArgumentNullException || @@ -74,8 +74,8 @@ public static void EvaluateResponseStatus(Exception e, ConnectionStringType type e.Message.Contains("was not found")) { response.Status = ConnectionStringValidationResult.ResultStatus.MalformedConnectionString; - response.StatusSummary = String.Format(Constants.MalformedConnectionStringDetails, appSettingName); - response.StatusDetails = Constants.GenericDetailsMessage; + response.Summary = String.Format(Constants.MalformedConnectionStringDetails, appSettingName); + response.Details = Constants.GenericDetailsMessage; response.Exception = e; } else if (e is ArgumentException && e.Message.Contains("entityPath is null") || @@ -84,15 +84,15 @@ public static void EvaluateResponseStatus(Exception e, ConnectionStringType type e.Message.Contains("The argument is null or white space")) { response.Status = ConnectionStringValidationResult.ResultStatus.MalformedConnectionString; - response.StatusSummary = String.Format(Constants.MalformedConnectionStringDetails, appSettingName); - response.StatusDetails = Constants.GenericDetailsMessage; + response.Summary = String.Format(Constants.MalformedConnectionStringDetails, appSettingName); + response.Details = Constants.GenericDetailsMessage; response.Exception = e; } else if (e.Message.Contains("InvalidSignature")) { response.Status = ConnectionStringValidationResult.ResultStatus.AuthFailure; - response.StatusSummary = String.Format(Constants.AuthFailureSummary, appSettingName) + " " + GetRelevantAuthFailureDocs(type); - response.StatusDetails = Constants.GenericDetailsMessage; + response.Summary = String.Format(Constants.AuthFailureSummary, appSettingName) + " " + GetRelevantAuthFailureDocs(type); + response.Details = Constants.GenericDetailsMessage; response.Exception = e; } else if ((e is ArgumentException && e.Message.Contains("Authentication")) || @@ -100,8 +100,8 @@ public static void EvaluateResponseStatus(Exception e, ConnectionStringType type e.Message.Contains("InvalidSignature")) { response.Status = ConnectionStringValidationResult.ResultStatus.AuthFailure; - response.StatusSummary = String.Format(Constants.AuthFailureSummary, appSettingName) + " " + GetRelevantAuthFailureDocs(type); - response.StatusDetails = Constants.GenericDetailsMessage; + response.Summary = String.Format(Constants.AuthFailureSummary, appSettingName) + " " + GetRelevantAuthFailureDocs(type); + response.Details = Constants.GenericDetailsMessage; response.Exception = e; } else if ((e is Azure.RequestFailedException && e.Message.Contains("failed to authenticate")) || @@ -109,8 +109,8 @@ public static void EvaluateResponseStatus(Exception e, ConnectionStringType type e.Message.Contains("InvalidSignature")) { response.Status = ConnectionStringValidationResult.ResultStatus.AuthFailure; - response.StatusSummary = String.Format(Constants.AuthFailureSummary, appSettingName) + " " + GetRelevantAuthFailureDocs(type); - response.StatusDetails = Constants.GenericDetailsMessage; + response.Summary = String.Format(Constants.AuthFailureSummary, appSettingName) + " " + GetRelevantAuthFailureDocs(type); + response.Details = Constants.GenericDetailsMessage; response.Exception = e; } else if (e.Message.Contains("Ip has been prevented to connect to the endpoint")) @@ -118,25 +118,25 @@ public static void EvaluateResponseStatus(Exception e, ConnectionStringType type response.Status = ConnectionStringValidationResult.ResultStatus.Forbidden; if (e.Message.Contains("AuthenticationFailed")) { - response.StatusSummary = String.Format(Constants.AuthFailureSummary, appSettingName) + " " + GetRelevantAuthFailureDocs(type); - response.StatusDetails = Constants.GenericDetailsMessage; + response.Summary = String.Format(Constants.AuthFailureSummary, appSettingName) + " " + GetRelevantAuthFailureDocs(type); + response.Details = Constants.GenericDetailsMessage; } else { - response.StatusSummary = "Access to the "+ type +" resource is restricted."; + response.Summary = "Access to the "+ type +" resource is restricted."; switch (type) { case ConnectionStringType.ServiceBus: - response.StatusDetails = Constants.ServiceBusAccessRestrictedDetails; + response.Details = Constants.ServiceBusAccessRestrictedDetails; break; case ConnectionStringType.EventHubs: - response.StatusDetails = Constants.EventHubAccessRestrictedDetails; + response.Details = Constants.EventHubAccessRestrictedDetails; break; case ConnectionStringType.StorageAccount: case ConnectionStringType.BlobStorageAccount: case ConnectionStringType.QueueStorageAccount: case ConnectionStringType.FileShareStorageAccount: - response.StatusDetails = Constants.StorageAccessRestrictedDetails; + response.Details = Constants.StorageAccessRestrictedDetails; break; } } @@ -147,33 +147,33 @@ public static void EvaluateResponseStatus(Exception e, ConnectionStringType type if (((StorageException)e).RequestInformation.HttpStatusCode == 401) { response.Status = ConnectionStringValidationResult.ResultStatus.AuthFailure; - response.StatusSummary = String.Format(Constants.AuthFailureSummary, appSettingName) + " " + GetRelevantAuthFailureDocs(type); - response.StatusDetails = Constants.GenericDetailsMessage; + response.Summary = String.Format(Constants.AuthFailureSummary, appSettingName) + " " + GetRelevantAuthFailureDocs(type); + response.Details = Constants.GenericDetailsMessage; } else if (((StorageException)e).RequestInformation.HttpStatusCode == 403) { response.Status = ConnectionStringValidationResult.ResultStatus.Forbidden; if (e.Message.Contains("AuthenticationFailed")) { - response.StatusSummary = String.Format(Constants.AuthFailureSummary, appSettingName) + " " + GetRelevantAuthFailureDocs(type); - response.StatusDetails = Constants.GenericDetailsMessage; + response.Summary = String.Format(Constants.AuthFailureSummary, appSettingName) + " " + GetRelevantAuthFailureDocs(type); + response.Details = Constants.GenericDetailsMessage; } else { - response.StatusSummary = "Access to the " + type + " resource is restricted."; + response.Summary = "Access to the " + type + " resource is restricted."; switch (type) { case ConnectionStringType.ServiceBus: - response.StatusDetails = Constants.ServiceBusAccessRestrictedDetails; + response.Details = Constants.ServiceBusAccessRestrictedDetails; break; case ConnectionStringType.EventHubs: - response.StatusDetails = Constants.EventHubAccessRestrictedDetails; + response.Details = Constants.EventHubAccessRestrictedDetails; break; case ConnectionStringType.StorageAccount: case ConnectionStringType.BlobStorageAccount: case ConnectionStringType.QueueStorageAccount: case ConnectionStringType.FileShareStorageAccount: - response.StatusDetails = Constants.StorageAccessRestrictedDetails; + response.Details = Constants.StorageAccessRestrictedDetails; break; } } @@ -183,7 +183,7 @@ public static void EvaluateResponseStatus(Exception e, ConnectionStringType type else { response.Status = ConnectionStringValidationResult.ResultStatus.UnknownError; - response.StatusSummary = Constants.UnknownErrorSummary; + response.Summary = Constants.UnknownErrorSummary; response.Exception = e; } } diff --git a/DiagnosticsExtension/Models/ConnectionStringValidator/ConnectionStringValidationResult.cs b/DiagnosticsExtension/Models/ConnectionStringValidator/ConnectionStringValidationResult.cs index a1a2db50..7d6e66a6 100644 --- a/DiagnosticsExtension/Models/ConnectionStringValidator/ConnectionStringValidationResult.cs +++ b/DiagnosticsExtension/Models/ConnectionStringValidator/ConnectionStringValidationResult.cs @@ -22,12 +22,9 @@ public class ConnectionStringValidationResult public ResultStatus? Status; [Newtonsoft.Json.JsonIgnore] public string IdentityType; - [JsonProperty("Summary")] - public string StatusSummary; - [JsonProperty("Details")] - public string StatusDetails; + public string Summary; + public string Details; public string StatusText => Status?.ToString(); - public Exception Exception; public string ExceptionMessage => Exception?.Message; [Newtonsoft.Json.JsonIgnore] diff --git a/DiagnosticsExtension/Models/ConnectionStringValidator/EventHubsValidator.cs b/DiagnosticsExtension/Models/ConnectionStringValidator/EventHubsValidator.cs index e888ed97..4a26918a 100644 --- a/DiagnosticsExtension/Models/ConnectionStringValidator/EventHubsValidator.cs +++ b/DiagnosticsExtension/Models/ConnectionStringValidator/EventHubsValidator.cs @@ -157,8 +157,8 @@ async public Task ValidateViaAppsettingAsync(s if (e.Message.Contains("The messaging entity") && e.Message.Contains("could not be found")) { response.Status = ConnectionStringValidationResult.ResultStatus.EntityNotFound; - response.StatusSummary = String.Format(Constants.EventHubEntityNotFoundSummary, entityName); - response.StatusDetails = Constants.EventHubEntityNotFoundDetails; + response.Summary = String.Format(Constants.EventHubEntityNotFoundSummary, entityName); + response.Details = Constants.EventHubEntityNotFoundDetails; response.Exception = e; } else if (isManagedIdentityConnection) diff --git a/DiagnosticsExtension/Models/ConnectionStringValidator/ManagedIdentityConnectionResponseUtility.cs b/DiagnosticsExtension/Models/ConnectionStringValidator/ManagedIdentityConnectionResponseUtility.cs index 5557e4cc..5bcc599d 100644 --- a/DiagnosticsExtension/Models/ConnectionStringValidator/ManagedIdentityConnectionResponseUtility.cs +++ b/DiagnosticsExtension/Models/ConnectionStringValidator/ManagedIdentityConnectionResponseUtility.cs @@ -23,20 +23,20 @@ public static void EvaluateResponseStatus(Exception e, ConnectionStringType type if (e is ManagedIdentityException) { response.Status = ConnectionStringValidationResult.ResultStatus.ManagedIdentityConnectionFailed; - response.StatusSummary = ((ManagedIdentityException)e).MessageSummary; - response.StatusDetails = ((ManagedIdentityException)e).MessageDetails; + response.Summary = ((ManagedIdentityException)e).MessageSummary; + response.Details = ((ManagedIdentityException)e).MessageDetails; } else if (e is UnauthorizedAccessException && e.Message.Contains("unauthorized") || e.Message.Contains("Unauthorized") || e.Message.Contains("request is not authorized")) { response.Status = ConnectionStringValidationResult.ResultStatus.ManagedIdentityAuthFailure; - response.StatusSummary = Constants.AuthorizationFailure; + response.Summary = Constants.AuthorizationFailure; if (response.IdentityType == "System") { - response.StatusDetails = String.Format(Constants.SystemAssignedAuthFailure, GetTargetConnectionAppSettingName(type, appSettingName)); + response.Details = String.Format(Constants.SystemAssignedAuthFailure, GetTargetConnectionAppSettingName(type, appSettingName)); } else { - response.StatusDetails = String.Format(Constants.UserAssignedAuthFailure, GetTargetConnectionAppSettingName(type, appSettingName)); + response.Details = String.Format(Constants.UserAssignedAuthFailure, GetTargetConnectionAppSettingName(type, appSettingName)); } response.Exception = e; @@ -44,31 +44,31 @@ public static void EvaluateResponseStatus(Exception e, ConnectionStringType type else if (e is AuthenticationFailedException && e.Message.Contains("ManagedIdentityCredential")) { response.Status = ConnectionStringValidationResult.ResultStatus.ManagedIdentityNotConfigured; - response.StatusSummary = "Your app is configured to use identity based connection but does not have a system assigned managed identity assigned. Refer here for details."; + response.Summary = "Your app is configured to use identity based connection but does not have a system assigned managed identity assigned. Refer here for details."; } else if (e.Message.Contains("fullyQualifiedNamespace")) { response.Status = ConnectionStringValidationResult.ResultStatus.FullyQualifiedNamespaceMissing; - response.StatusSummary = "The app setting " + appSettingName + "__fullyQualifiedNamespace was not found or is set to a blank value. Refer here for details."; + response.Summary = "The app setting " + appSettingName + "__fullyQualifiedNamespace was not found or is set to a blank value. Refer here for details."; } else if (e.InnerException != null && e.InnerException.Message.Contains("The remote name could not be resolved")) // queue and blob { response.Status = ConnectionStringValidationResult.ResultStatus.DnsLookupFailed; - response.StatusSummary = String.Format(Constants.StorageAccountResourceNotFound, GetTargetConnectionAppSettingName(type, appSettingName)); + response.Summary = String.Format(Constants.StorageAccountResourceNotFound, GetTargetConnectionAppSettingName(type, appSettingName)); } else if (e.Message.Contains("No such host is known")) // event hub and service bus { response.Status = ConnectionStringValidationResult.ResultStatus.DnsLookupFailed; - response.StatusSummary = String.Format(Constants.FQNamespaceResourceNotFound, appSettingName); - response.StatusDetails = Constants.GenericDetailsMessage; + response.Summary = String.Format(Constants.FQNamespaceResourceNotFound, appSettingName); + response.Details = Constants.GenericDetailsMessage; response.Exception = e; } else { response.Status = ConnectionStringValidationResult.ResultStatus.UnknownError; - response.StatusSummary = Constants.UnknownErrorSummary; + response.Summary = Constants.UnknownErrorSummary; response.Exception = e; } } diff --git a/DiagnosticsExtension/Models/ConnectionStringValidator/ServiceBusValidator.cs b/DiagnosticsExtension/Models/ConnectionStringValidator/ServiceBusValidator.cs index c4c78259..38cd588d 100644 --- a/DiagnosticsExtension/Models/ConnectionStringValidator/ServiceBusValidator.cs +++ b/DiagnosticsExtension/Models/ConnectionStringValidator/ServiceBusValidator.cs @@ -173,8 +173,8 @@ async public Task ValidateViaAppsettingAsync(s if (e.Message.Contains("Put token failed") && e.Message.Contains("could not be found")) { response.Status = ConnectionStringValidationResult.ResultStatus.EntityNotFound; - response.StatusSummary = String.Format(Constants.ServiceBusEntityNotFoundSummary, entityName); - response.StatusDetails = Constants.ServiceBusEntityNotFoundDetails; + response.Summary = String.Format(Constants.ServiceBusEntityNotFoundSummary, entityName); + response.Details = Constants.ServiceBusEntityNotFoundDetails; response.Exception = e; } else if (isManagedIdentityConnection) From 8854e89d91099449fae24d226f7ba959a6ce7bdf Mon Sep 17 00:00:00 2001 From: Sid Krishna Date: Wed, 27 Jul 2022 14:41:39 -0700 Subject: [PATCH 26/26] Removed duplicate package reference --- DiagnosticsExtension/packages.config | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/DiagnosticsExtension/packages.config b/DiagnosticsExtension/packages.config index 346d10c8..69154da5 100644 --- a/DiagnosticsExtension/packages.config +++ b/DiagnosticsExtension/packages.config @@ -49,7 +49,6 @@ - @@ -90,4 +89,4 @@ -
\ No newline at end of file +