Skip to content
This repository was archived by the owner on Feb 28, 2024. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
6d962f9
Code changes for Blob, Queue, Servicebus and EventHub of New SDK vers…
gajibillik Feb 1, 2022
424453a
Modified the code as per the comments
gajibillik Feb 2, 2022
fd98f98
changed the code as per the comments
gajibillik Feb 17, 2022
2c880c7
Changes done as per the sid's comments in PR
gajibillik Feb 25, 2022
973dad8
Added comments for queue, eventhub and servicebus
gajibillik Feb 25, 2022
858dd6a
Code has been changed as per the comments in PR
gajibillik Mar 2, 2022
0561022
Code modified as per the comments
gajibillik Mar 9, 2022
6df0d71
Changed the code as per the comments
gajibillik Mar 11, 2022
46ab0ff
Changed the code as per the comments
gajibillik Mar 24, 2022
062c3a3
Removed ommented code
gajibillik Mar 24, 2022
db7a575
jwt Token related code changes
gajibillik Mar 25, 2022
2ec976c
Updated error messages and refactored ManagedIdentityException to sup…
Mar 29, 2022
7a375a3
Additional changes for error messages
Mar 29, 2022
e397ada
Additional error msg and logic changes
Mar 29, 2022
d01dd31
Code changes as per the latest comments
gajibillik Apr 1, 2022
3566ed8
Code changes of latest comments on fobidden case
gajibillik Apr 5, 2022
1dc1279
Improved error and mitigation messages and fixed a few relevant bugs …
Apr 7, 2022
25cb261
Updated Authentication failed error messages with docs links
Apr 8, 2022
4ee3cf1
Added error handling logic for key vault reference resolution failure…
Apr 8, 2022
aa895f7
Returning a StatusSummary for UnknownError status to keep client side…
Apr 8, 2022
9d880e7
Added support for entity not found error handling. Quotes around val…
Apr 19, 2022
ef2aa54
Code changes as per the comments
gajibillik Apr 19, 2022
c8fca3b
Code changes as per the comments
gajibillik Apr 19, 2022
e997f66
Code changes as per the latest comments.
gajibillik Apr 25, 2022
474051a
PR feedback on messaging.
Apr 27, 2022
54fccf6
Modified the code as per the comments by yifguoMSFT
gajibillik May 13, 2022
5a35676
Merge branch 'sidkri/527_Networkvalidator_V3' of https://github.com/g…
gajibillik May 13, 2022
1254010
Merge branch 'feature/network-troubleshooter-managed-identity-support…
sidkri Jul 27, 2022
8854e89
Removed duplicate package reference
sidkri Jul 27, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// -----------------------------------------------------------------------
// -----------------------------------------------------------------------
// <copyright file="ConnectionStringValidationController.cs" company="Microsoft Corporation">
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See LICENSE in the project root for license information.
Expand Down Expand Up @@ -37,6 +37,9 @@ public ConnectionStringValidationController()
new MySqlValidator(),
new KeyVaultValidator(),
new StorageValidator(),
new BlobStorageValidator(),
new QueueStorageValidator(),
new FileShareStorageValidator(),
new ServiceBusValidator(),
new EventHubsValidator(),
new HttpValidator()
Expand Down Expand Up @@ -72,25 +75,31 @@ public async Task<HttpResponseMessage> 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;
}

/// <summary>
/// This method is used to validate connection information via appsetting.
/// </summary>
/// <param name="appSettingName">This should be the configured appsetting key/connection property of the function. </param>
/// <param name="type">This should be the type of Azure service being connected.</param>
/// <param name="entityName">This is valid only for servicebus and eventhub. Need not be passed for other azure services.</param>
/// <returns>ConnectionStringValidationResult</returns>
[HttpGet]
[Route("validateappsetting")]
public async Task<HttpResponseMessage> ValidateAppSetting(string appSettingName, string type)
[Route("validateappsettingforfunctionapp")]
public async Task<HttpResponseMessage> ValidateAppSettingForFunctionApp(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");
}
}
}
}
}
118 changes: 99 additions & 19 deletions DiagnosticsExtension/DiagnosticsExtension.csproj

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
// -----------------------------------------------------------------------
// <copyright file="StorageValidator.cs" company="Microsoft Corporation">
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See LICENSE in the project root for license information.
// </copyright>
// -----------------------------------------------------------------------

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;
using Azure.Core;
using Azure.Identity;

namespace DiagnosticsExtension.Models.ConnectionStringValidator
{
public class BlobStorageValidator : IConnectionStringValidator
{
public string ProviderName => "Microsoft.WindowsAzure.Storage";
public ConnectionStringType Type => ConnectionStringType.BlobStorageAccount;
public async Task<ConnectionStringValidationResult> 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))
{
// Connection String
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
{
// Managed Identity
isManagedIdentityConnection = true;
string serviceUriString = ManagedIdentityConnectionResponseUtility.ResolveManagedIdentityCommonProperty(appSettingName, ConnectionStringValidationResult.ManagedIdentityCommonProperty.blobServiceUri);
if (string.IsNullOrEmpty(serviceUriString))
{
serviceUriString = ManagedIdentityConnectionResponseUtility.ResolveManagedIdentityCommonProperty(appSettingName, ConnectionStringValidationResult.ManagedIdentityCommonProperty.serviceUri);
}
if (!string.IsNullOrEmpty(serviceUriString))
{
string clientIdAppSettingKey = Environment.GetEnvironmentVariables().Keys.Cast<string>().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));
}
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 (string.IsNullOrEmpty(appSettingClientIdValue))
{
throw new ManagedIdentityException(String.Format(Constants.ManagedIdentityClientIdEmptySummary, clientIdAppSettingKey),
String.Format(Constants.ManagedIdentityClientIdEmptyDetails, appSettingName));
}
response.IdentityType = Constants.User;
client = new BlobServiceClient(serviceUri, ManagedIdentityCredentialTokenValidator.GetValidatedCredential(appSettingClientIdValue,appSettingName));
}
else
{
// Creating client using System assigned managed identity
response.IdentityType = Constants.System;
client = new BlobServiceClient(serviceUri, new Azure.Identity.ManagedIdentityCredential());
}
}
else
{
string serviceuriAppSettingName = Environment.GetEnvironmentVariables().Keys.Cast<string>().Where(k => k.StartsWith(appSettingName) && k.ToLower().EndsWith("serviceuri")).FirstOrDefault();
if (serviceuriAppSettingName == null)
{
throw new ManagedIdentityException(Constants.BlobServiceUriMissingSummary);
}
throw new ManagedIdentityException(String.Format(Constants.BlobServiceUriEmptySummary, serviceuriAppSettingName));

}
}
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();

response.Status = ConnectionStringValidationResult.ResultStatus.Success;
}
catch (Exception e)
{
if (isManagedIdentityConnection)
{
ManagedIdentityConnectionResponseUtility.EvaluateResponseStatus(e, Type, ref response, appSettingName);
}
else
{
ConnectionStringResponseUtility.EvaluateResponseStatus(e, Type, ref response, appSettingName);
}
}

return response;
}
public async Task<ConnectionStringValidationResult> ValidateAsync(string connStr, string clientId = null)
{
throw new NotImplementedException();
}
public async Task<bool> IsValidAsync(string connStr)
{
throw new NotImplementedException();
}

}
}
Loading