4094 Kusto AAD Authentication Refactor (#1115)

* 4094 Upgraded Kusto.Data and Kusto.Language to 9.0.3. Refactored KustoServiceLayer to use KustoConnectionStringBuilder instead of Sql.

* 4094 Refactored KustoClient>Initialize to take connectionString as optional. Removed unused properties from ConnectionService>ParseConnectionString

* 4094 Updated Kusto.Data and Kusto.Language nuget packages to 9.0.4. Removed IsDedicatedAdminConnection function in ConnectionService.

* 4094 Fixed unit tests
This commit is contained in:
Justin M
2020-11-20 11:54:40 -08:00
committed by GitHub
parent 67c7e20c13
commit fd84367008
13 changed files with 65 additions and 301 deletions

View File

@@ -117,8 +117,11 @@ namespace Microsoft.Kusto.ServiceLayer.DataSource.DataSourceIntellisense
var query = "let fn = " + parameters + " { };";
var code = KustoCode.ParseAndAnalyze(query);
var let = code.Syntax.GetFirstDescendant<LetStatement>();
var variable = let.Name.ReferencedSymbol as VariableSymbol;
var function = variable.Type as FunctionSymbol;
FunctionSymbol function = let.Name.ReferencedSymbol is VariableSymbol variable
? variable.Type as FunctionSymbol
: let.Name.ReferencedSymbol as FunctionSymbol;
return function.Signatures[0].Parameters;
}

View File

@@ -14,7 +14,6 @@ using Kusto.Data.Exceptions;
using Kusto.Data.Net.Client;
using Kusto.Language;
using Kusto.Language.Editor;
using Microsoft.Data.SqlClient;
using Microsoft.Kusto.ServiceLayer.Connection;
using Microsoft.Kusto.ServiceLayer.DataSource.DataSourceIntellisense;
using Microsoft.Kusto.ServiceLayer.Utility;
@@ -36,26 +35,21 @@ namespace Microsoft.Kusto.ServiceLayer.DataSource
/// </summary>
public GlobalState SchemaState { get; private set; }
public string ClusterName { get; }
public string ClusterName { get; private set; }
public string DatabaseName { get; private set; }
public KustoClient(string connectionString, string azureAccountToken, string ownerUri)
{
_ownerUri = ownerUri;
ClusterName = GetClusterName(connectionString);
var dbName = new SqlConnectionStringBuilder(connectionString).InitialCatalog;
SetDatabaseName(dbName);
Initialize(ClusterName, DatabaseName, azureAccountToken);
Initialize(azureAccountToken, connectionString);
SchemaState = LoadSchemaState();
}
private void SetDatabaseName(string databaseName)
private string ParseDatabaseName(string databaseName)
{
var regex = new Regex(@"(?<=\().+?(?=\))");
DatabaseName = regex.IsMatch(databaseName)
return regex.IsMatch(databaseName)
? regex.Match(databaseName).Value
: databaseName;
}
@@ -85,9 +79,9 @@ namespace Microsoft.Kusto.ServiceLayer.DataSource
DatabaseName, ClusterName);
}
private void Initialize(string clusterName, string databaseName, string azureAccountToken)
private void Initialize(string azureAccountToken, string connectionString = "")
{
var stringBuilder = GetKustoConnectionStringBuilder(clusterName, databaseName, azureAccountToken, "", "");
var stringBuilder = GetKustoConnectionStringBuilder(azureAccountToken, connectionString);
_kustoQueryProvider = KustoClientFactory.CreateCslQueryProvider(stringBuilder);
_kustoAdminProvider = KustoClientFactory.CreateCslAdminProvider(stringBuilder);
}
@@ -97,68 +91,26 @@ namespace Microsoft.Kusto.ServiceLayer.DataSource
string azureAccountToken = ConnectionService.Instance.RefreshAzureToken(_ownerUri);
_kustoQueryProvider.Dispose();
_kustoAdminProvider.Dispose();
Initialize(ClusterName, DatabaseName, azureAccountToken);
Initialize(azureAccountToken);
}
/// <summary>
/// Extracts the cluster name from the connectionstring. The string looks like the following:
/// "Data Source=clustername.kusto.windows.net;User ID=;Password=;Pooling=False;Application Name=azdata-GeneralConnection"
/// <summary>
/// <param name="connectionString">A connection string coming over the Data management protocol</param>
private string GetClusterName(string connectionString)
private KustoConnectionStringBuilder GetKustoConnectionStringBuilder(string userToken, string connectionString)
{
var csb = new SqlConnectionStringBuilder(connectionString);
ValidationUtils.IsTrue<ArgumentException>(!string.IsNullOrWhiteSpace(userToken),
$"the Kusto authentication is not specified - either set {nameof(userToken)}");
// If there is no https:// prefix, add it
Uri uri;
if ((Uri.TryCreate(csb.DataSource, UriKind.Absolute, out uri) ||
Uri.TryCreate("https://" + csb.DataSource, UriKind.Absolute, out uri)) &&
(uri.Scheme == Uri.UriSchemeHttp || uri.Scheme == Uri.UriSchemeHttps))
{
return uri.AbsoluteUri;
}
throw new ArgumentException("Expected a URL of the form clustername.kusto.windows.net");
}
private KustoConnectionStringBuilder GetKustoConnectionStringBuilder(string clusterName, string databaseName,
string userToken, string applicationClientId, string applicationKey)
{
ValidationUtils.IsNotNull(clusterName, nameof(clusterName));
ValidationUtils.IsTrue<ArgumentException>(
!string.IsNullOrWhiteSpace(userToken)
|| (!string.IsNullOrWhiteSpace(applicationClientId) && !string.IsNullOrWhiteSpace(applicationKey)),
$"the Kusto authentication is not specified - either set {nameof(userToken)}, or set {nameof(applicationClientId)} and {nameof(applicationKey)}");
var kcsb = new KustoConnectionStringBuilder
{
DataSource = clusterName,
// Perform federated auth based on the AAD user token, or based on the AAD application client id and key.
FederatedSecurity = true
};
if (!string.IsNullOrWhiteSpace(databaseName))
{
kcsb.InitialCatalog = databaseName;
}
if (!string.IsNullOrWhiteSpace(userToken))
{
kcsb.UserToken = userToken;
}
if (!string.IsNullOrWhiteSpace(applicationClientId))
{
kcsb.ApplicationClientId = applicationClientId;
}
if (!string.IsNullOrWhiteSpace(applicationKey))
{
kcsb.ApplicationKey = applicationKey;
}
return kcsb;
var stringBuilder = string.IsNullOrWhiteSpace(connectionString)
? new KustoConnectionStringBuilder(ClusterName, DatabaseName)
: new KustoConnectionStringBuilder(connectionString);
ClusterName = stringBuilder.DataSource;
var databaseName = ParseDatabaseName(stringBuilder.InitialCatalog);
DatabaseName = databaseName;
stringBuilder.InitialCatalog = databaseName;
ValidationUtils.IsNotNull(ClusterName, nameof(ClusterName));
return stringBuilder.WithAadUserTokenAuthentication(userToken);
}
private ClientRequestProperties GetClientRequestProperties(CancellationToken cancellationToken)
@@ -310,7 +262,7 @@ namespace Microsoft.Kusto.ServiceLayer.DataSource
public void UpdateDatabase(string databaseName)
{
SetDatabaseName(databaseName);
DatabaseName = ParseDatabaseName(databaseName);
SchemaState = LoadSchemaState();
}

View File

@@ -65,12 +65,12 @@ namespace Microsoft.Kusto.ServiceLayer.DataSource.Metadata
{
var databaseDetails = new List<DatabaseInfo>();
if (typeof(DatabaseMetadata) == clusterDBDetails.FirstOrDefault().GetType())
if (clusterDBDetails.FirstOrDefault() is DatabaseMetadata)
{
foreach (var dbDetail in clusterDBDetails)
{
DatabaseInfo databaseInfo = new DatabaseInfo();
Int64.TryParse(dbDetail.SizeInMB.ToString(), out long sum_OriginalSize);
long.TryParse(dbDetail.SizeInMB, out long sum_OriginalSize);
databaseInfo.Options["name"] = dbDetail.Name;
databaseInfo.Options["sizeInMB"] = (sum_OriginalSize / (1024 * 1024)).ToString();
databaseDetails.Add(databaseInfo);