From 13a7d4aa2b126b3f9c9c89963f4d25381aa815ef Mon Sep 17 00:00:00 2001 From: Justin M <63619224+JustinMDotNet@users.noreply.github.com> Date: Tue, 23 Feb 2021 17:29:09 -0800 Subject: [PATCH] Kusto NoAuth authentication (#1161) * Added username and password to DataSourceConnectionDetails. Refactored KustoClient>GetKustoConnectionStringBuilder to accept no username or password for no credentials authentication. * Removed invalid Unit Test and added 2 unit tests for testing authentication type. * Added validation for dstsAuth and AzureMFA in DataSourceFactory. Added unit test for validation. --- .../Contracts/DataSourceConnectionDetails.cs | 2 ++ .../DataSource/DataSourceFactory.cs | 14 +++++++--- .../DataSource/KustoClient.cs | 17 ++++++----- .../DataSource/KustoClientTests.cs | 28 +++++++++++-------- 4 files changed, 39 insertions(+), 22 deletions(-) diff --git a/src/Microsoft.Kusto.ServiceLayer/DataSource/Contracts/DataSourceConnectionDetails.cs b/src/Microsoft.Kusto.ServiceLayer/DataSource/Contracts/DataSourceConnectionDetails.cs index cd696371..bb87987e 100644 --- a/src/Microsoft.Kusto.ServiceLayer/DataSource/Contracts/DataSourceConnectionDetails.cs +++ b/src/Microsoft.Kusto.ServiceLayer/DataSource/Contracts/DataSourceConnectionDetails.cs @@ -7,5 +7,7 @@ namespace Microsoft.Kusto.ServiceLayer.DataSource.Contracts public string UserToken { get; set; } public string ConnectionString { get; set; } public string AuthenticationType { get; set; } + public string UserName { get; set; } + public string Password { get; set; } } } \ No newline at end of file diff --git a/src/Microsoft.Kusto.ServiceLayer/DataSource/DataSourceFactory.cs b/src/Microsoft.Kusto.ServiceLayer/DataSource/DataSourceFactory.cs index 24b27736..b22dd108 100644 --- a/src/Microsoft.Kusto.ServiceLayer/DataSource/DataSourceFactory.cs +++ b/src/Microsoft.Kusto.ServiceLayer/DataSource/DataSourceFactory.cs @@ -8,8 +8,8 @@ using Microsoft.SqlTools.ServiceLayer.Connection.ReliableConnection; using Microsoft.Kusto.ServiceLayer.DataSource.Intellisense; using Microsoft.Kusto.ServiceLayer.LanguageServices; using Microsoft.Kusto.ServiceLayer.LanguageServices.Contracts; -using Microsoft.Kusto.ServiceLayer.Workspace.Contracts; using Microsoft.Kusto.ServiceLayer.Utility; +using Microsoft.Kusto.ServiceLayer.Workspace.Contracts; namespace Microsoft.Kusto.ServiceLayer.DataSource { @@ -18,8 +18,6 @@ namespace Microsoft.Kusto.ServiceLayer.DataSource { public IDataSource Create(DataSourceType dataSourceType, ConnectionDetails connectionDetails, string ownerUri) { - ValidationUtils.IsArgumentNotNullOrWhiteSpace(connectionDetails.AccountToken, nameof(connectionDetails.AccountToken)); - switch (dataSourceType) { case DataSourceType.Kusto: @@ -39,13 +37,21 @@ namespace Microsoft.Kusto.ServiceLayer.DataSource private DataSourceConnectionDetails MapKustoConnectionDetails(ConnectionDetails connectionDetails) { + if (connectionDetails.AuthenticationType == "dstsAuth" || connectionDetails.AuthenticationType == "AzureMFA") + { + ValidationUtils.IsTrue(!string.IsNullOrWhiteSpace(connectionDetails.AccountToken), + $"The Kusto User Token is not specified - set {nameof(connectionDetails.AccountToken)}"); + } + return new DataSourceConnectionDetails { ServerName = connectionDetails.ServerName, DatabaseName = connectionDetails.DatabaseName, ConnectionString = connectionDetails.ConnectionString, AuthenticationType = connectionDetails.AuthenticationType, - UserToken = connectionDetails.AccountToken + UserToken = connectionDetails.AccountToken, + UserName = connectionDetails.UserName, + Password = connectionDetails.Password }; } diff --git a/src/Microsoft.Kusto.ServiceLayer/DataSource/KustoClient.cs b/src/Microsoft.Kusto.ServiceLayer/DataSource/KustoClient.cs index 2c062e7e..c766a298 100644 --- a/src/Microsoft.Kusto.ServiceLayer/DataSource/KustoClient.cs +++ b/src/Microsoft.Kusto.ServiceLayer/DataSource/KustoClient.cs @@ -74,9 +74,6 @@ namespace Microsoft.Kusto.ServiceLayer.DataSource private KustoConnectionStringBuilder GetKustoConnectionStringBuilder(DataSourceConnectionDetails connectionDetails) { - ValidationUtils.IsTrue(!string.IsNullOrWhiteSpace(connectionDetails.UserToken), - $"The Kusto User Token is not specified - set {nameof(connectionDetails.UserToken)}"); - var stringBuilder = string.IsNullOrWhiteSpace(connectionDetails.ConnectionString) ? new KustoConnectionStringBuilder(connectionDetails.ServerName, connectionDetails.DatabaseName) : new KustoConnectionStringBuilder(connectionDetails.ConnectionString); @@ -87,10 +84,16 @@ namespace Microsoft.Kusto.ServiceLayer.DataSource stringBuilder.InitialCatalog = databaseName; ValidationUtils.IsNotNull(ClusterName, nameof(ClusterName)); - - return connectionDetails.AuthenticationType == "dstsAuth" - ? stringBuilder.WithDstsUserTokenAuthentication(connectionDetails.UserToken) - : stringBuilder.WithAadUserTokenAuthentication(connectionDetails.UserToken); + + switch (connectionDetails.AuthenticationType) + { + case "AzureMFA": return stringBuilder.WithAadUserTokenAuthentication(connectionDetails.UserToken); + case "dstsAuth": return stringBuilder.WithDstsUserTokenAuthentication(connectionDetails.UserToken); + default: + return string.IsNullOrWhiteSpace(connectionDetails.UserName) && string.IsNullOrWhiteSpace(connectionDetails.Password) + ? stringBuilder + : stringBuilder.WithKustoBasicAuthentication(connectionDetails.UserName, connectionDetails.Password); + } } private ClientRequestProperties GetClientRequestProperties(CancellationToken cancellationToken) diff --git a/test/Microsoft.Kusto.ServiceLayer.UnitTests/DataSource/KustoClientTests.cs b/test/Microsoft.Kusto.ServiceLayer.UnitTests/DataSource/KustoClientTests.cs index 396aa4af..64552b1c 100644 --- a/test/Microsoft.Kusto.ServiceLayer.UnitTests/DataSource/KustoClientTests.cs +++ b/test/Microsoft.Kusto.ServiceLayer.UnitTests/DataSource/KustoClientTests.cs @@ -7,17 +7,19 @@ namespace Microsoft.Kusto.ServiceLayer.UnitTests.DataSource { public class KustoClientTests { - [Test] - public void Constructor_Throws_ArgumentException_For_MissingToken() - { - var connectionDetails = new DataSourceConnectionDetails - { - UserToken = "" - }; - - Assert.Throws(() => new KustoClient(connectionDetails, "ownerUri")); - } + [TestCase("dstsAuth")] + [TestCase("AzureMFA")] + public void Constructor_Throws_ArgumentException_For_MissingToken(string authType) + { + var connectionDetails = new DataSourceConnectionDetails + { + UserToken = "", + AuthenticationType = authType + }; + Assert.Throws(() => new KustoClient(connectionDetails, "ownerUri")); + } + [Test] public void Constructor_Sets_ClusterName_With_DefaultDatabaseName() { @@ -38,6 +40,8 @@ namespace Microsoft.Kusto.ServiceLayer.UnitTests.DataSource [TestCase("dstsAuth")] [TestCase("AzureMFA")] + [TestCase("NoAuth")] + [TestCase("SqlLogin")] public void Constructor_Creates_Client_With_Valid_AuthenticationType(string authenticationType) { string clusterName = "https://fake.url.com"; @@ -46,7 +50,9 @@ namespace Microsoft.Kusto.ServiceLayer.UnitTests.DataSource UserToken = "UserToken", ServerName = clusterName, DatabaseName = "FakeDatabaseName", - AuthenticationType = authenticationType + AuthenticationType = authenticationType, + UserName = authenticationType == "SqlLogin" ? "username": null, + Password = authenticationType == "SqlLogin" ? "password": null }; var client = new KustoClient(connectionDetails, "ownerUri");