Support passing Http proxy URL and Strict SSL flag to Authenticator (#2256)

This commit is contained in:
Cheena Malhotra
2023-10-11 10:49:47 -07:00
committed by GitHub
parent 67ae2192c3
commit a3b42e43bd
6 changed files with 110 additions and 6 deletions

View File

@@ -162,6 +162,7 @@ namespace Microsoft.SqlTools.Authentication
private IPublicClientApplication CreatePublicClientAppInstance(string authority, string audience) =>
PublicClientApplicationBuilder.Create(this.configuration.AppClientId)
.WithAuthority(authority, audience)
.WithHttpClientFactory(new HttpClientProxyFactory(this.configuration.HttpProxyUrl, this.configuration.HttpProxyStrictSSL))
.WithClientName(this.configuration.AppName)
.WithLogging(Utils.MSALLogCallback)
.WithDefaultRedirectUri()

View File

@@ -31,11 +31,23 @@ namespace Microsoft.SqlTools.Authentication.Utility
/// </summary>
public string CacheFileName { get; set; }
public AuthenticatorConfiguration(string appClientId, string appName, string cacheFolderPath, string cacheFileName) {
/// <summary>
/// Proxy URL defined by end user.
/// </summary>
public string? HttpProxyUrl { get; set; }
/// <summary>
/// Whether the proxy server certificate must be verified against list of configured CAs.
/// </summary>
public bool HttpProxyStrictSSL { get; set; }
public AuthenticatorConfiguration(string appClientId, string appName, string cacheFolderPath, string cacheFileName, string? httpProxyUrl = null, bool httpProxyStrictSSL = true) {
AppClientId = appClientId;
AppName = appName;
CacheFolderPath = cacheFolderPath;
CacheFileName = cacheFileName;
HttpProxyUrl = httpProxyUrl;
HttpProxyStrictSSL = httpProxyStrictSSL;
}
}
}

View File

@@ -0,0 +1,75 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
using System.Net;
using System.Net.Security;
using Microsoft.Identity.Client;
using SqlToolsLogger = Microsoft.SqlTools.Utility.Logger;
namespace Microsoft.SqlTools.Authentication.Utility
{
/// <summary>
/// Implements Http Client Factory for Microsoft Identity Client to support proxy authentication.
/// </summary>
public class HttpClientProxyFactory : IMsalHttpClientFactory
{
private readonly HttpClient s_httpClient;
/// <summary>
/// Default constructor to construct instance with proxy URL provided.
/// </summary>
/// <param name="proxyUrl">Proxy URL to be used for network access.</param>
/// <param name="proxyStrictSSL">Whether or not proxy server certficate must be strictly validated.</param>
public HttpClientProxyFactory(string? proxyUrl, bool proxyStrictSSL)
{
if (proxyUrl != null)
{
var webProxy = new WebProxy(
new Uri(proxyUrl),
BypassOnLocal: false);
var proxyHttpClientHandler = new HttpClientHandler
{
Proxy = webProxy,
UseProxy = true,
ServerCertificateCustomValidationCallback = (request, certs, chain, policyErrors) =>
{
if (policyErrors != SslPolicyErrors.None)
{
SqlToolsLogger.Error("Proxy Server Certificate Validation failed with error: " + policyErrors.ToString());
}
if (proxyStrictSSL)
{
return policyErrors != SslPolicyErrors.None;
}
// Bypass Proxy server certificate validation.
else
{
SqlToolsLogger.Information("Proxy Server Certificate Validation bypassed as requested.");
return true;
}
}
};
s_httpClient = new HttpClient(proxyHttpClientHandler);
SqlToolsLogger.Verbose($"Received Http Proxy URL is used to instantiate HttpClientFactory");
}
else
{
s_httpClient = new HttpClient();
}
}
/// <summary>
/// Gets Http Client instance
/// </summary>
/// <returns></returns>
public HttpClient GetHttpClient()
{
return s_httpClient;
}
}
}

View File

@@ -70,6 +70,12 @@ namespace Microsoft.SqlTools.Utility
case "-help":
ShouldExit = true;
return;
case "-http-proxy-url":
HttpProxyUrl = args[++i];
break;
case "-http-proxy-strict-ssl":
HttpProxyStrictSSL = true;
break;
case "-service-name":
ServiceName = args[++i];
break;
@@ -136,6 +142,16 @@ namespace Microsoft.SqlTools.Utility
/// </summary>
public string Locale { get; private set; }
/// <summary>
/// Custom Http Proxy URL as specified in Azure Data Studio
/// </summary>
public string? HttpProxyUrl { get; private set; }
/// <summary>
/// Specifies whether the proxy server certificate should be verified against the list of supplied CAs.
/// </summary>
public bool HttpProxyStrictSSL { get; private set; }
/// <summary>
/// Name of service that is receiving command options
/// </summary>

View File

@@ -1190,7 +1190,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Connection
}
var cachePath = Path.Combine(applicationPath, applicationName, AzureTokenFolder);
return new Authenticator(new(ApplicationClientId, applicationName, cachePath, MsalCacheName), () => this.encryptionKeys);
return new Authenticator(new(ApplicationClientId, applicationName, cachePath, MsalCacheName, commandOptions.HttpProxyUrl, commandOptions.HttpProxyStrictSSL), () => this.encryptionKeys);
}
private Task HandleEncryptionKeysNotificationEvent(EncryptionKeysChangeParams @params, EventContext context)

View File

@@ -302,11 +302,11 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement
((DatabaseInfo)databaseViewInfo.ObjectInfo).IsFilesTabSupported = true;
((DatabaseInfo)databaseViewInfo.ObjectInfo).Filegroups = GetFileGroups(smoDatabase, databaseViewInfo);
}
}
if (prototype is DatabasePrototype160)
{
((DatabaseInfo)databaseViewInfo.ObjectInfo).IsLedgerDatabase = smoDatabase.IsLedger;
}
if (prototype is DatabasePrototype160)
{
((DatabaseInfo)databaseViewInfo.ObjectInfo).IsLedgerDatabase = smoDatabase.IsLedger;
}
databaseScopedConfigurationsCollection = smoDatabase.IsSupportedObject<DatabaseScopedConfiguration>() ? smoDatabase.DatabaseScopedConfigurations : null;
databaseViewInfo.FileTypesOptions = displayFileTypes.Values.ToArray();