diff --git a/Snowflake.Data.Tests/IntegrationTests/SFConnectionIT.cs b/Snowflake.Data.Tests/IntegrationTests/SFConnectionIT.cs index 5a4976162..91539670b 100644 --- a/Snowflake.Data.Tests/IntegrationTests/SFConnectionIT.cs +++ b/Snowflake.Data.Tests/IntegrationTests/SFConnectionIT.cs @@ -3,6 +3,7 @@ */ using System.Data.Common; +using Snowflake.Data.Core.Session; namespace Snowflake.Data.Tests.IntegrationTests { diff --git a/Snowflake.Data.Tests/Mock/MockOkta.cs b/Snowflake.Data.Tests/Mock/MockOkta.cs index 8c39bf74e..f53f78287 100644 --- a/Snowflake.Data.Tests/Mock/MockOkta.cs +++ b/Snowflake.Data.Tests/Mock/MockOkta.cs @@ -7,6 +7,7 @@ using System.Net.Http; using System.Threading; using System.Threading.Tasks; +using Snowflake.Data.Core.Authenticator.Okta.Models; namespace Snowflake.Data.Tests.Mock { diff --git a/Snowflake.Data.Tests/Mock/MockSnowflakeDbConnection.cs b/Snowflake.Data.Tests/Mock/MockSnowflakeDbConnection.cs index c6d8f0698..ec540602f 100644 --- a/Snowflake.Data.Tests/Mock/MockSnowflakeDbConnection.cs +++ b/Snowflake.Data.Tests/Mock/MockSnowflakeDbConnection.cs @@ -9,6 +9,7 @@ using System.Data; using System.Threading; using System.Threading.Tasks; +using Snowflake.Data.Core.Session; namespace Snowflake.Data.Tests.Mock { diff --git a/Snowflake.Data.Tests/UnitTests/ArrowResultSetTest.cs b/Snowflake.Data.Tests/UnitTests/ArrowResultSetTest.cs index cf8746b75..22b219d29 100755 --- a/Snowflake.Data.Tests/UnitTests/ArrowResultSetTest.cs +++ b/Snowflake.Data.Tests/UnitTests/ArrowResultSetTest.cs @@ -13,6 +13,7 @@ using Apache.Arrow.Ipc; using NUnit.Framework; using Snowflake.Data.Core; +using Snowflake.Data.Core.Session; using Snowflake.Data.Tests.Util; namespace Snowflake.Data.Tests.UnitTests diff --git a/Snowflake.Data.Tests/UnitTests/ChunkDownloaderFactoryTest.cs b/Snowflake.Data.Tests/UnitTests/ChunkDownloaderFactoryTest.cs index cf8b952a0..33a2fe25e 100644 --- a/Snowflake.Data.Tests/UnitTests/ChunkDownloaderFactoryTest.cs +++ b/Snowflake.Data.Tests/UnitTests/ChunkDownloaderFactoryTest.cs @@ -2,6 +2,8 @@ * Copyright (c) 2023 Snowflake Computing Inc. All rights reserved. */ +using Snowflake.Data.Core.Session; + namespace Snowflake.Data.Tests.UnitTests { using NUnit.Framework; diff --git a/Snowflake.Data.Tests/UnitTests/ChunkStreamingParserTest.cs b/Snowflake.Data.Tests/UnitTests/ChunkStreamingParserTest.cs index e32541440..e19aef4e6 100644 --- a/Snowflake.Data.Tests/UnitTests/ChunkStreamingParserTest.cs +++ b/Snowflake.Data.Tests/UnitTests/ChunkStreamingParserTest.cs @@ -2,12 +2,13 @@ * Copyright (c) 2023 Snowflake Computing Inc. All rights reserved. */ +using Snowflake.Data.Core; + namespace Snowflake.Data.Tests.UnitTests { using NUnit.Framework; - using Snowflake.Data.Client; + using Client; using Snowflake.Data.Configuration; - using Snowflake.Data.Core; using System; using System.IO; using System.Text; @@ -31,19 +32,12 @@ public void AfterTest() SFConfiguration.Instance().ChunkParserVersion = _chunkParserVersionDefault; // Return to default version } - public IChunkParser getParser(string data) - { - byte[] bytes = Encoding.UTF8.GetBytes(data); - Stream stream = new MemoryStream(bytes); - return ChunkParserFactory.Instance.GetParser(ResultFormat.JSON, stream); - } - [Test] public async Task TestParsingEmptyChunk() { // Create sample data for parser string data = "[ ]"; - IChunkParser parser = getParser(data); + IChunkParser parser = GetParser(data); SFResultChunk chunk = new SFResultChunk(new string[0, 0]); @@ -60,7 +54,7 @@ public async Task TestParsingEmptyArraysInChunk() { // Create sample data for parser string data = "[ [], [] ]"; - IChunkParser parser = getParser(data); + IChunkParser parser = GetParser(data); SFResultChunk chunk = new SFResultChunk(new string[2, 0]); @@ -77,7 +71,7 @@ public async Task TestParsingNonJsonArrayChunk() { // Create a sample data using data not contained in an array string data = "[ \"1\", \"1.234\", \"abcde\" ]"; - IChunkParser parser = getParser(data); + IChunkParser parser = GetParser(data); SFResultChunk chunk = new SFResultChunk(new string[1, 3]); @@ -95,7 +89,7 @@ public void TestThrowingExceptionOnUsupportedNestedJsonArrays() { // Create a sample data using non-array data and an array string data = "[ \"1\", \"1.234\", \"abcde\", [\"2\", \"5.678\", \"fghi\"] ]"; - IChunkParser parser = getParser(data); + IChunkParser parser = GetParser(data); SFResultChunk chunk = new SFResultChunk(new string[1, 3]); @@ -108,7 +102,7 @@ public void TestThrowingExceptionForJsonObjectElementsInAnArray() { // Create a sample data using JSON objects instead string data = "[ {\"1\", \"1.234\", \"abcde\"}, {\"2\", \"5.678\", \"fghi\"} ]"; - IChunkParser parser = getParser(data); + IChunkParser parser = GetParser(data); SFResultChunk chunk = new SFResultChunk(new string[2, 3]); @@ -122,7 +116,7 @@ public async Task TestParsingSimpleChunk() { // Create sample data for parser string data = "[ [\"1\", \"1.234\", \"abcde\"], [\"2\", \"5.678\", \"fghi\"] ]"; - IChunkParser parser = getParser(data); + IChunkParser parser = GetParser(data); SFResultChunk chunk = new SFResultChunk(new string[2, 3]); @@ -144,7 +138,7 @@ public async Task TestParsingChunkWithNullValue() { // Create sample data that contain null values string data = "[ [null, \"1.234\", null], [\"2\", null, \"fghi\"] ]"; - IChunkParser parser = getParser(data); + IChunkParser parser = GetParser(data); SFResultChunk chunk = new SFResultChunk(new string[2, 3]); @@ -160,5 +154,12 @@ public async Task TestParsingChunkWithNullValue() Assert.AreEqual(null, chunk.ExtractCell(1).SafeToString()); Assert.AreEqual("fghi", chunk.ExtractCell(2).SafeToString()); } + + private static IChunkParser GetParser(string data) + { + byte[] bytes = Encoding.UTF8.GetBytes(data); + Stream stream = new MemoryStream(bytes); + return ChunkParserFactory.Instance.GetParser(ResultFormat.JSON, stream); + } } } diff --git a/Snowflake.Data.Tests/UnitTests/Core/Authenticator/Okta/IdpTokenRestRequestFactoryTests.cs b/Snowflake.Data.Tests/UnitTests/Core/Authenticator/Okta/IdpTokenRestRequestFactoryTests.cs new file mode 100644 index 000000000..74dc17983 --- /dev/null +++ b/Snowflake.Data.Tests/UnitTests/Core/Authenticator/Okta/IdpTokenRestRequestFactoryTests.cs @@ -0,0 +1,37 @@ +using System; +using System.Security; +using NUnit.Framework; +using Snowflake.Data.Core.Authenticator.Okta; +using Snowflake.Data.Core.Session; + +namespace Snowflake.Data.Tests.UnitTests.Core.Authenticator.Okta +{ + public class IdpTokenRestRequestFactoryTests + { + private IdpTokenRestRequestFactory _idpTokenRestRequestFactory; + + [SetUp] + public void SetUp() + { + _idpTokenRestRequestFactory = new IdpTokenRestRequestFactory(); + } + + [Test] + public void TestIfCreateCorrectRequest() + { + // arrange + var tokenUrl = new Uri("https://test.com/"); + var session = new SFSession("ACCOUNT=account;USER=username1;", new SecureString()); + + // act + var actual = _idpTokenRestRequestFactory.Create(tokenUrl, session); + + // assert + Assert.AreEqual(tokenUrl, actual.Url); + Assert.AreEqual(session.connectionTimeout, actual.RestTimeout); + Assert.AreEqual(TimeSpan.FromSeconds(16), actual.HttpTimeout); + Assert.AreEqual("username1", actual.JsonBody.Username); + Assert.AreEqual("", actual.JsonBody.Password); + } + } +} \ No newline at end of file diff --git a/Snowflake.Data.Tests/UnitTests/Core/Authenticator/Okta/SamlRestRequestFactoryTests.cs b/Snowflake.Data.Tests/UnitTests/Core/Authenticator/Okta/SamlRestRequestFactoryTests.cs new file mode 100644 index 000000000..d8613a937 --- /dev/null +++ b/Snowflake.Data.Tests/UnitTests/Core/Authenticator/Okta/SamlRestRequestFactoryTests.cs @@ -0,0 +1,36 @@ +using System; +using System.Threading; +using NUnit.Framework; +using Snowflake.Data.Core.Authenticator.Okta; + +namespace Snowflake.Data.Tests.UnitTests.Core.Authenticator.Okta +{ + public class SamlRestRequestFactoryTests + { + private ISamlRestRequestFactory _samlRestRequestFactory; + + [SetUp] + public void SetUp() + { + _samlRestRequestFactory = new SamlRestRequestFactory(); + } + + [Test] + public void TestIfCorrectSamlRestRequestIsCreated() + { + // arrange + var uri = new Uri("https://test.com"); + var onetimeToken = Guid.NewGuid().ToString(); + var timeout = TimeSpan.Parse("00:10:00"); + + // act + var actual = _samlRestRequestFactory.Create(uri, onetimeToken, timeout); + + // assert + Assert.AreEqual(uri, actual.Url); + Assert.AreEqual(timeout, actual.RestTimeout); + Assert.AreEqual(Timeout.InfiniteTimeSpan, actual.HttpTimeout); + Assert.AreEqual(onetimeToken, actual.OnetimeToken); + } + } +} \ No newline at end of file diff --git a/Snowflake.Data.Tests/UnitTests/FastMemoryStreamTest.cs b/Snowflake.Data.Tests/UnitTests/FastMemoryStreamTest.cs index e755a4604..4a95cb210 100644 --- a/Snowflake.Data.Tests/UnitTests/FastMemoryStreamTest.cs +++ b/Snowflake.Data.Tests/UnitTests/FastMemoryStreamTest.cs @@ -11,7 +11,7 @@ namespace Snowflake.Data.Tests.UnitTests [TestFixture] class FastMemoryStreamTest { - FastMemoryStream _fastMemoryStream; + private FastMemoryStream _fastMemoryStream; [SetUp] public void BeforeTest() diff --git a/Snowflake.Data.Tests/UnitTests/FileBackedOutputStreamTest.cs b/Snowflake.Data.Tests/UnitTests/FileBackedOutputStreamTest.cs index 8e5a2da27..fc88574e3 100644 --- a/Snowflake.Data.Tests/UnitTests/FileBackedOutputStreamTest.cs +++ b/Snowflake.Data.Tests/UnitTests/FileBackedOutputStreamTest.cs @@ -7,7 +7,7 @@ using NUnit.Framework; using Snowflake.Data.Core.FileTransfer; -namespace Snowflake.Data.Tests +namespace Snowflake.Data.Tests.UnitTests { public class FileBackedOutputStreamTest { diff --git a/Snowflake.Data.Tests/UnitTests/Logger/SFLoggerTest.cs b/Snowflake.Data.Tests/UnitTests/Logger/SFLoggerTest.cs index 710a8d645..c7ad66bd2 100644 --- a/Snowflake.Data.Tests/UnitTests/Logger/SFLoggerTest.cs +++ b/Snowflake.Data.Tests/UnitTests/Logger/SFLoggerTest.cs @@ -2,13 +2,12 @@ * Copyright (c) 2023 Snowflake Computing Inc. All rights reserved. */ +using NUnit.Framework; using Snowflake.Data.Configuration; +using Snowflake.Data.Log; -namespace Snowflake.Data.Tests.UnitTests +namespace Snowflake.Data.Tests.UnitTests.Logger { - using NUnit.Framework; - using Snowflake.Data.Log; - [TestFixture, NonParallelizable] class SFLoggerTest { diff --git a/Snowflake.Data.Tests/UnitTests/SFAuthenticatorFactoryTest.cs b/Snowflake.Data.Tests/UnitTests/SFAuthenticatorFactoryTest.cs index 3157619ae..9e990b236 100644 --- a/Snowflake.Data.Tests/UnitTests/SFAuthenticatorFactoryTest.cs +++ b/Snowflake.Data.Tests/UnitTests/SFAuthenticatorFactoryTest.cs @@ -2,6 +2,9 @@ * Copyright (c) 2012-2023 Snowflake Computing Inc. All rights reserved. */ +using Snowflake.Data.Core.Authenticator.Okta; +using Snowflake.Data.Core.Session; + namespace Snowflake.Data.Tests.UnitTests { using NUnit.Framework; @@ -25,7 +28,7 @@ private IAuthenticator GetAuthenticator(string authenticatorName, string extraPa [Test] public void TestGetAuthenticatorBasic() { - _authenticator = GetAuthenticator(BasicAuthenticator.AUTH_NAME); + _authenticator = GetAuthenticator(BasicAuthenticator.AuthName); Assert.IsInstanceOf(_authenticator); } diff --git a/Snowflake.Data.Tests/UnitTests/SFDbParameterCollectionTest.cs b/Snowflake.Data.Tests/UnitTests/SFDbParameterCollectionTest.cs index c3f798f97..8da3da81d 100644 --- a/Snowflake.Data.Tests/UnitTests/SFDbParameterCollectionTest.cs +++ b/Snowflake.Data.Tests/UnitTests/SFDbParameterCollectionTest.cs @@ -2,14 +2,15 @@ * Copyright (c) 2012-2023 Snowflake Computing Inc. All rights reserved. */ -namespace Snowflake.Data.Tests +using System; +using System.Collections; +using NUnit.Framework; +using Snowflake.Data.Client; +using Snowflake.Data.Core; +using Snowflake.Data.Core.Session; + +namespace Snowflake.Data.Tests.UnitTests { - using NUnit.Framework; - using Snowflake.Data.Client; - using Snowflake.Data.Core; - using System; - using System.Collections; - [TestFixture] class SFDbParameterCollectionTest { diff --git a/Snowflake.Data.Tests/UnitTests/SFDbParameterTest.cs b/Snowflake.Data.Tests/UnitTests/SFDbParameterTest.cs index 7674d096a..b87be3918 100644 --- a/Snowflake.Data.Tests/UnitTests/SFDbParameterTest.cs +++ b/Snowflake.Data.Tests/UnitTests/SFDbParameterTest.cs @@ -2,13 +2,14 @@ * Copyright (c) 2012-2023 Snowflake Computing Inc. All rights reserved. */ -namespace Snowflake.Data.Tests -{ - using NUnit.Framework; - using Snowflake.Data.Client; - using Snowflake.Data.Core; - using System.Data; +using System.Data; +using NUnit.Framework; +using Snowflake.Data.Client; +using Snowflake.Data.Core; +using Snowflake.Data.Core.Session; +namespace Snowflake.Data.Tests.UnitTests +{ [TestFixture] class SFDbParameterTest { diff --git a/Snowflake.Data.Tests/UnitTests/SFFileTransferAgentTests.cs b/Snowflake.Data.Tests/UnitTests/SFFileTransferAgentTests.cs index 5d81a610e..2be86ff94 100644 --- a/Snowflake.Data.Tests/UnitTests/SFFileTransferAgentTests.cs +++ b/Snowflake.Data.Tests/UnitTests/SFFileTransferAgentTests.cs @@ -2,6 +2,9 @@ * Copyright (c) 2012-2023 Snowflake Computing Inc. All rights reserved. */ +using Snowflake.Data.Core.FileTransfer.StorageClient; +using Snowflake.Data.Core.Session; + namespace Snowflake.Data.Tests.UnitTests { using NUnit.Framework; diff --git a/Snowflake.Data.Tests/UnitTests/SFOktaTest.cs b/Snowflake.Data.Tests/UnitTests/SFOktaTest.cs index 5de0c6c06..86a7e6016 100644 --- a/Snowflake.Data.Tests/UnitTests/SFOktaTest.cs +++ b/Snowflake.Data.Tests/UnitTests/SFOktaTest.cs @@ -2,6 +2,7 @@ using Snowflake.Data.Client; using Snowflake.Data.Core; using System.Net.Http; +using Snowflake.Data.Core.Session; namespace Snowflake.Data.Tests.UnitTests { diff --git a/Snowflake.Data.Tests/UnitTests/SFReusableChunkTest.cs b/Snowflake.Data.Tests/UnitTests/SFReusableChunkTest.cs index 4ca4eec79..ee570a4a4 100755 --- a/Snowflake.Data.Tests/UnitTests/SFReusableChunkTest.cs +++ b/Snowflake.Data.Tests/UnitTests/SFReusableChunkTest.cs @@ -3,6 +3,7 @@ */ using System; +using Snowflake.Data.Core.Session; namespace Snowflake.Data.Tests.UnitTests { diff --git a/Snowflake.Data.Tests/UnitTests/SFSessionPropertyTest.cs b/Snowflake.Data.Tests/UnitTests/SFSessionPropertyTest.cs index 37fa3d815..4b76b5e59 100644 --- a/Snowflake.Data.Tests/UnitTests/SFSessionPropertyTest.cs +++ b/Snowflake.Data.Tests/UnitTests/SFSessionPropertyTest.cs @@ -8,6 +8,7 @@ using NUnit.Framework; using Snowflake.Data.Client; using Snowflake.Data.Core.Authenticator; +using Snowflake.Data.Core.Session; namespace Snowflake.Data.Tests.UnitTests { @@ -18,7 +19,7 @@ class SFSessionPropertyTest public void TestThatPropertiesAreParsed(TestCase testcase) { // act - var properties = SFSessionProperties.parseConnectionString( + var properties = SFSessionProperties.ParseConnectionString( testcase.ConnectionString, testcase.SecurePassword); @@ -36,7 +37,7 @@ public void TestThatItFailsForWrongConnectionParameter(string connectionString, { // act var exception = Assert.Throws( - () => SFSessionProperties.parseConnectionString(connectionString, null) + () => SFSessionProperties.ParseConnectionString(connectionString, null) ); // assert @@ -51,7 +52,7 @@ public void TestThatItFailsIfNoAccountSpecified(string connectionString) { // act var exception = Assert.Throws( - () => SFSessionProperties.parseConnectionString(connectionString, null) + () => SFSessionProperties.ParseConnectionString(connectionString, null) ); // assert diff --git a/Snowflake.Data.Tests/UnitTests/SFSessionTest.cs b/Snowflake.Data.Tests/UnitTests/SFSessionTest.cs index b9530b83b..20efa1bee 100644 --- a/Snowflake.Data.Tests/UnitTests/SFSessionTest.cs +++ b/Snowflake.Data.Tests/UnitTests/SFSessionTest.cs @@ -3,6 +3,7 @@ */ using Snowflake.Data.Configuration; +using Snowflake.Data.Core.Session; using Snowflake.Data.Log; namespace Snowflake.Data.Tests.UnitTests @@ -20,7 +21,7 @@ public void TestSessionGoneWhenClose() Mock.MockCloseSessionGone restRequester = new Mock.MockCloseSessionGone(); SFSession sfSession = new SFSession("account=test;user=test;password=test", null, restRequester); sfSession.Open(); - sfSession.close(); // no exception is raised. + sfSession.Close(); // no exception is raised. } [Test] diff --git a/Snowflake.Data.Tests/UnitTests/SFStatementTest.cs b/Snowflake.Data.Tests/UnitTests/SFStatementTest.cs index 330b19f96..aa1ed8281 100755 --- a/Snowflake.Data.Tests/UnitTests/SFStatementTest.cs +++ b/Snowflake.Data.Tests/UnitTests/SFStatementTest.cs @@ -2,6 +2,8 @@ * Copyright (c) 2012-2019 Snowflake Computing Inc. All rights reserved. */ +using Snowflake.Data.Core.Session; + namespace Snowflake.Data.Tests.UnitTests { using Snowflake.Data.Core; diff --git a/Snowflake.Data.Tests/UnitTests/Session/EasyLoggingStarterTest.cs b/Snowflake.Data.Tests/UnitTests/Session/EasyLoggingStarterTest.cs index 00a2ed9b7..1d364f350 100644 --- a/Snowflake.Data.Tests/UnitTests/Session/EasyLoggingStarterTest.cs +++ b/Snowflake.Data.Tests/UnitTests/Session/EasyLoggingStarterTest.cs @@ -8,6 +8,7 @@ using NUnit.Framework; using Snowflake.Data.Configuration; using Snowflake.Data.Core; +using Snowflake.Data.Core.Session; using Snowflake.Data.Core.Tools; using Snowflake.Data.Log; diff --git a/Snowflake.Data.Tests/UnitTests/Session/SFHttpClientPropertiesTest.cs b/Snowflake.Data.Tests/UnitTests/Session/SFHttpClientPropertiesTest.cs index 72421f588..724ab4680 100644 --- a/Snowflake.Data.Tests/UnitTests/Session/SFHttpClientPropertiesTest.cs +++ b/Snowflake.Data.Tests/UnitTests/Session/SFHttpClientPropertiesTest.cs @@ -6,6 +6,7 @@ using Moq; using NUnit.Framework; using Snowflake.Data.Core; +using Snowflake.Data.Core.Session; using Snowflake.Data.Tests.Util; namespace Snowflake.Data.Tests.UnitTests.Session @@ -115,7 +116,7 @@ public void TestExtractProperties(PropertiesTestCase testCase) // arrange var proxyExtractorMock = new Moq.Mock(); var extractor = new SFSessionHttpClientProperties.Extractor(proxyExtractorMock.Object); - var properties = SFSessionProperties.parseConnectionString(testCase.conectionString, null); + var properties = SFSessionProperties.ParseConnectionString(testCase.conectionString, null); var proxyProperties = new SFSessionHttpClientProxyProperties(); proxyExtractorMock .Setup(e => e.ExtractProperties(properties)) diff --git a/Snowflake.Data.Tests/UnitTests/Session/SFHttpClientProxyPropertiesTest.cs b/Snowflake.Data.Tests/UnitTests/Session/SFHttpClientProxyPropertiesTest.cs index a39d9bede..aae6c3418 100644 --- a/Snowflake.Data.Tests/UnitTests/Session/SFHttpClientProxyPropertiesTest.cs +++ b/Snowflake.Data.Tests/UnitTests/Session/SFHttpClientProxyPropertiesTest.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using NUnit.Framework; using Snowflake.Data.Core; +using Snowflake.Data.Core.Session; namespace Snowflake.Data.Tests.UnitTests.Session { @@ -17,7 +18,7 @@ public void ShouldExtractProxyProperties(ProxyPropertiesTestCase testCase) { // given var extractor = new SFSessionHttpClientProxyProperties.Extractor(); - var properties = SFSessionProperties.parseConnectionString(testCase.conectionString, null); + var properties = SFSessionProperties.ParseConnectionString(testCase.conectionString, null); // when var proxyProperties = extractor.ExtractProperties(properties); diff --git a/Snowflake.Data/Client/SnowflakeDbConnection.cs b/Snowflake.Data/Client/SnowflakeDbConnection.cs index b773a0150..d04e31de8 100755 --- a/Snowflake.Data/Client/SnowflakeDbConnection.cs +++ b/Snowflake.Data/Client/SnowflakeDbConnection.cs @@ -9,6 +9,7 @@ using System.Threading.Tasks; using System.Data; using System.Threading; +using Snowflake.Data.Core.Session; using Snowflake.Data.Log; namespace Snowflake.Data.Client @@ -159,7 +160,7 @@ public override void Close() } else { - SfSession.close(); + SfSession.Close(); } SfSession = null; } @@ -377,7 +378,7 @@ protected override void Dispose(bool disposing) } else { - SfSession?.close(); + SfSession?.Close(); SfSession = null; _connectionState = ConnectionState.Closed; } diff --git a/Snowflake.Data/Client/SnowflakeDbException.cs b/Snowflake.Data/Client/SnowflakeDbException.cs index 014ad62e1..c16a4d225 100755 --- a/Snowflake.Data/Client/SnowflakeDbException.cs +++ b/Snowflake.Data/Client/SnowflakeDbException.cs @@ -6,6 +6,7 @@ using System.Data.Common; using System.Resources; using Snowflake.Data.Core; +using Snowflake.Data.Core.Session; namespace Snowflake.Data.Client { @@ -74,21 +75,21 @@ public SnowflakeDbException(Exception innerException, string sqlState, SFError e static string FormatExceptionMessage(SFError error, object[] args, string sqlState, - string queryId) - { - return FormatExceptionMessage(string.Format(rm.GetString(error.ToString()), args) - , error.GetAttribute().errorCode - , sqlState - , queryId); - } - - static string FormatExceptionMessage(string errorMessage, - int vendorCode, - string sqlState, string queryId) - { - return string.Format("Error: {0} SqlState: {1}, VendorCode: {2}, QueryId: {3}", - errorMessage, sqlState, vendorCode, queryId); + { + return FormatExceptionMessage(string.Format(rm.GetString(error.ToString()), args) + , error.GetAttribute().errorCode + , sqlState + , queryId); + } + + static string FormatExceptionMessage(string errorMessage, + int vendorCode, + string sqlState, + string queryId) + { + return string.Format("Error: {0} SqlState: {1}, VendorCode: {2}, QueryId: {3}", + errorMessage, sqlState, vendorCode, queryId); } } } diff --git a/Snowflake.Data/Core/ArrowResultSet.cs b/Snowflake.Data/Core/ArrowResultSet.cs index 31e0eccca..3d5a180f8 100755 --- a/Snowflake.Data/Core/ArrowResultSet.cs +++ b/Snowflake.Data/Core/ArrowResultSet.cs @@ -9,6 +9,7 @@ using System.Threading.Tasks; using Apache.Arrow.Ipc; using Snowflake.Data.Client; +using Snowflake.Data.Core.Session; using Snowflake.Data.Log; namespace Snowflake.Data.Core diff --git a/Snowflake.Data/Core/Authenticator/AuthenticatorFactory.cs b/Snowflake.Data/Core/Authenticator/AuthenticatorFactory.cs new file mode 100644 index 000000000..779b7ea96 --- /dev/null +++ b/Snowflake.Data/Core/Authenticator/AuthenticatorFactory.cs @@ -0,0 +1,82 @@ +using System; +using Snowflake.Data.Client; +using Snowflake.Data.Core.Authenticator.Okta; +using Snowflake.Data.Core.Session; +using Snowflake.Data.Log; + +namespace Snowflake.Data.Core.Authenticator +{ + /// + /// Authenticator Factory to build authenticators + /// + internal sealed class AuthenticatorFactory + { + private static readonly SFLogger s_logger = SFLoggerFactory.GetLogger(); + /// + /// Generate the authenticator given the session + /// + /// session that requires the authentication + /// authenticator + /// when authenticator is unknown + internal static IAuthenticator GetAuthenticator(SFSession session) + { + string type = session.properties[SFSessionProperty.AUTHENTICATOR]; + if (type.Equals(BasicAuthenticator.AuthName, StringComparison.InvariantCultureIgnoreCase)) + { + return new BasicAuthenticator(session); + } + + if (type.Equals(ExternalBrowserAuthenticator.AUTH_NAME, StringComparison.InvariantCultureIgnoreCase)) + { + return new ExternalBrowserAuthenticator(session); + } + + if (type.Equals(KeyPairAuthenticator.AUTH_NAME, StringComparison.InvariantCultureIgnoreCase)) + { + // Get private key path or private key from connection settings + if (!session.properties.TryGetValue(SFSessionProperty.PRIVATE_KEY_FILE, out var pkPath) && + !session.properties.TryGetValue(SFSessionProperty.PRIVATE_KEY, out var pkContent)) + { + // There is no PRIVATE_KEY_FILE defined, can't authenticate with key-pair + var invalidStringDetail = + "Missing required PRIVATE_KEY_FILE or PRIVATE_KEY for key pair authentication"; + var error = new SnowflakeDbException( + SFError.INVALID_CONNECTION_STRING, + new object[] { invalidStringDetail }); + s_logger.Error(error.Message, error); + throw error; + } + + return new KeyPairAuthenticator(session); + } + if (type.Equals(OAuthAuthenticator.AUTH_NAME, StringComparison.InvariantCultureIgnoreCase)) + { + // Get private key path or private key from connection settings + if (!session.properties.TryGetValue(SFSessionProperty.TOKEN, out var pkPath)) + { + // There is no TOKEN defined, can't authenticate with oauth + string invalidStringDetail = + "Missing required TOKEN for Oauth authentication"; + var error = new SnowflakeDbException( + SFError.INVALID_CONNECTION_STRING, + new object[] { invalidStringDetail }); + s_logger.Error(error.Message, error); + throw error; + } + + return new OAuthAuthenticator(session); + } + // Okta would provide a url of form: https://xxxxxx.okta.com or https://xxxxxx.oktapreview.com or https://vanity.url/snowflake/okta + if (type.Contains("okta") && type.StartsWith("https://")) + { + return new OktaAuthenticator(session, type, new SamlRestRequestFactory(), new IdpTokenRestRequestFactory()); + } + + var e = new SnowflakeDbException(SFError.UNKNOWN_AUTHENTICATOR, type); + + s_logger.Error("Unknown authenticator", e); + + throw e; + } + } +} \ No newline at end of file diff --git a/Snowflake.Data/Core/Authenticator/BaseAuthenticator.cs b/Snowflake.Data/Core/Authenticator/BaseAuthenticator.cs new file mode 100644 index 000000000..4ce006462 --- /dev/null +++ b/Snowflake.Data/Core/Authenticator/BaseAuthenticator.cs @@ -0,0 +1,92 @@ +using System.Threading; +using System.Threading.Tasks; +using Snowflake.Data.Core.Session; + +namespace Snowflake.Data.Core.Authenticator +{ + /// + /// A base implementation for all authenticators to create and send a login request. + /// + internal abstract class BaseAuthenticator + { + // The name of the authenticator. + private readonly string _authName; + + // The session which created this authenticator. + protected SFSession Session; + + // The client environment properties + private readonly LoginRequestClientEnv _clientEnv = SFEnvironment.ClientEnv; + + /// + /// The abstract base for all authenticators. + /// + /// The session which created the authenticator. + protected BaseAuthenticator(SFSession session, string authName) + { + this.Session = session; + this._authName = authName; + // Update the value for insecureMode because it can be different for each session + _clientEnv.insecureMode = session.properties[SFSessionProperty.INSECUREMODE]; + if (session.properties.TryGetValue(SFSessionProperty.APPLICATION, out var applicationName)) + { + // If an application name has been specified in the connection setting, use it + // Otherwise, it will default to the running process name + _clientEnv.application = applicationName; + } + } + + //// + protected async Task LoginAsync(CancellationToken cancellationToken) + { + var loginRequest = BuildLoginRequest(); + + var response = await Session.restRequester.PostAsync(loginRequest, cancellationToken).ConfigureAwait(false); + + Session.ProcessLoginResponse(response); + } + + /// + protected void Login() + { + var loginRequest = BuildLoginRequest(); + + var response = Session.restRequester.Post(loginRequest); + + Session.ProcessLoginResponse(response); + } + + /// + /// Specialized authenticator data to add to the login request. + /// + /// The login request data to update. + protected abstract void SetSpecializedAuthenticatorData(ref LoginRequestData data); + + /// + /// Builds a simple login request. Each authenticator will fill the Data part with their + /// specialized information. The common Data attributes are already filled (clientAppId, + /// ClienAppVersion...). + /// + /// A login request to send to the server. + private SFRestRequest BuildLoginRequest() + { + // build uri + var loginUrl = Session.BuildLoginUrl(); + + var data = new LoginRequestData() + { + loginName = Session.properties[SFSessionProperty.USER], + accountName = Session.properties[SFSessionProperty.ACCOUNT], + clientAppId = SFEnvironment.DriverName, + clientAppVersion = SFEnvironment.DriverVersion, + clientEnv = _clientEnv, + SessionParameters = Session.ParameterMap, + Authenticator = _authName, + }; + + SetSpecializedAuthenticatorData(ref data); + + return Session.BuildTimeoutRestRequest(loginUrl, new LoginRequest() { data = data }); + } + } +} \ No newline at end of file diff --git a/Snowflake.Data/Core/Authenticator/BasicAuthenticator.cs b/Snowflake.Data/Core/Authenticator/BasicAuthenticator.cs index d7a7a29d1..edd639e00 100644 --- a/Snowflake.Data/Core/Authenticator/BasicAuthenticator.cs +++ b/Snowflake.Data/Core/Authenticator/BasicAuthenticator.cs @@ -5,35 +5,36 @@ using Snowflake.Data.Log; using System.Threading; using System.Threading.Tasks; +using Snowflake.Data.Core.Session; namespace Snowflake.Data.Core.Authenticator { class BasicAuthenticator : BaseAuthenticator, IAuthenticator { - public static readonly string AUTH_NAME = "snowflake"; - private static readonly SFLogger logger = SFLoggerFactory.GetLogger(); + public const string AuthName = "snowflake"; + private static readonly SFLogger s_logger = SFLoggerFactory.GetLogger(); - internal BasicAuthenticator(SFSession session) : base(session, AUTH_NAME) + internal BasicAuthenticator(SFSession session) : base(session, AuthName) { } /// async Task IAuthenticator.AuthenticateAsync(CancellationToken cancellationToken) { - await base.LoginAsync(cancellationToken); + await LoginAsync(cancellationToken); } /// void IAuthenticator.Authenticate() { - base.Login(); + Login(); } /// protected override void SetSpecializedAuthenticatorData(ref LoginRequestData data) { // Only need to add the password to Data for basic authentication - data.password = session.properties[SFSessionProperty.PASSWORD]; + data.password = Session.properties[SFSessionProperty.PASSWORD]; } } diff --git a/Snowflake.Data/Core/Authenticator/ExternalBrowserAuthenticator.cs b/Snowflake.Data/Core/Authenticator/ExternalBrowserAuthenticator.cs index d6ead6818..48cde7aab 100644 --- a/Snowflake.Data/Core/Authenticator/ExternalBrowserAuthenticator.cs +++ b/Snowflake.Data/Core/Authenticator/ExternalBrowserAuthenticator.cs @@ -13,6 +13,7 @@ using Snowflake.Data.Client; using System.Text.RegularExpressions; using System.Collections.Generic; +using Snowflake.Data.Core.Session; namespace Snowflake.Data.Core.Authenticator { @@ -56,11 +57,11 @@ async Task IAuthenticator.AuthenticateAsync(CancellationToken cancellationToken) logger.Debug("Get IdpUrl and ProofKey"); string loginUrl; - if (session._disableConsoleLogin) + if (Session._disableConsoleLogin) { var authenticatorRestRequest = BuildAuthenticatorRestRequest(localPort); var authenticatorRestResponse = - await session.restRequester.PostAsync( + await Session.restRequester.PostAsync( authenticatorRestRequest, cancellationToken ).ConfigureAwait(false); @@ -81,7 +82,7 @@ await session.restRequester.PostAsync( logger.Debug("Get the redirect SAML request"); _successEvent = new ManualResetEvent(false); httpListener.BeginGetContext(GetContextCallback, httpListener); - var timeoutInSec = int.Parse(session.properties[SFSessionProperty.BROWSER_RESPONSE_TIMEOUT]); + var timeoutInSec = int.Parse(Session.properties[SFSessionProperty.BROWSER_RESPONSE_TIMEOUT]); if (!_successEvent.WaitOne(timeoutInSec * 1000)) { logger.Warn("Browser response timeout"); @@ -107,10 +108,10 @@ void IAuthenticator.Authenticate() logger.Debug("Get IdpUrl and ProofKey"); string loginUrl; - if (session._disableConsoleLogin) + if (Session._disableConsoleLogin) { var authenticatorRestRequest = BuildAuthenticatorRestRequest(localPort); - var authenticatorRestResponse = session.restRequester.Post(authenticatorRestRequest); + var authenticatorRestResponse = Session.restRequester.Post(authenticatorRestRequest); authenticatorRestResponse.FilterFailedResponse(); loginUrl = authenticatorRestResponse.data.ssoUrl; @@ -128,7 +129,7 @@ void IAuthenticator.Authenticate() logger.Debug("Get the redirect SAML request"); _successEvent = new ManualResetEvent(false); httpListener.BeginGetContext(GetContextCallback, httpListener); - var timeoutInSec = int.Parse(session.properties[SFSessionProperty.BROWSER_RESPONSE_TIMEOUT]); + var timeoutInSec = int.Parse(Session.properties[SFSessionProperty.BROWSER_RESPONSE_TIMEOUT]); if (!_successEvent.WaitOne(timeoutInSec * 1000)) { logger.Warn("Browser response timeout"); @@ -246,17 +247,17 @@ private static string ValidateAndExtractToken(HttpListenerRequest request) private SFRestRequest BuildAuthenticatorRestRequest(int port) { - var fedUrl = session.BuildUri(RestPath.SF_AUTHENTICATOR_REQUEST_PATH); + var fedUrl = Session.BuildUri(RestPath.SF_AUTHENTICATOR_REQUEST_PATH); var data = new AuthenticatorRequestData() { - AccountName = session.properties[SFSessionProperty.ACCOUNT], + AccountName = Session.properties[SFSessionProperty.ACCOUNT], Authenticator = AUTH_NAME, BrowserModeRedirectPort = port.ToString(), }; - int connectionTimeoutSec = int.Parse(session.properties[SFSessionProperty.CONNECTION_TIMEOUT]); + int connectionTimeoutSec = int.Parse(Session.properties[SFSessionProperty.CONNECTION_TIMEOUT]); - return session.BuildTimeoutRestRequest(fedUrl, new AuthenticatorRequest() { Data = data }); + return Session.BuildTimeoutRestRequest(fedUrl, new AuthenticatorRequest() { Data = data }); } /// @@ -271,11 +272,11 @@ private string GetLoginUrl(string proofKey, int localPort) { Dictionary parameters = new Dictionary() { - { "login_name", session.properties[SFSessionProperty.USER]}, + { "login_name", Session.properties[SFSessionProperty.USER]}, { "proof_key", proofKey }, { "browser_mode_redirect_port", localPort.ToString() } }; - Uri loginUrl = session.BuildUri(RestPath.SF_CONSOLE_LOGIN, parameters); + Uri loginUrl = Session.BuildUri(RestPath.SF_CONSOLE_LOGIN, parameters); return loginUrl.ToString(); } diff --git a/Snowflake.Data/Core/Authenticator/IAuthenticator.cs b/Snowflake.Data/Core/Authenticator/IAuthenticator.cs index 150551f91..74f4fae2e 100644 --- a/Snowflake.Data/Core/Authenticator/IAuthenticator.cs +++ b/Snowflake.Data/Core/Authenticator/IAuthenticator.cs @@ -2,11 +2,9 @@ * Copyright (c) 2012-2021 Snowflake Computing Inc. All rights reserved. */ -using System; using System.Threading; using System.Threading.Tasks; using Snowflake.Data.Client; -using Snowflake.Data.Log; namespace Snowflake.Data.Core.Authenticator { @@ -17,7 +15,7 @@ namespace Snowflake.Data.Core.Authenticator internal interface IAuthenticator { /// - /// Process the authentication asynchronouly + /// Process the authentication asynchronously /// /// /// @@ -30,174 +28,4 @@ internal interface IAuthenticator /// void Authenticate(); } - - /// - /// Types of authenticators - /// - internal enum SFAuthenticatorType - { - SNOWFLAKE, - OKTA, - } - /// - /// A base implementation for all authenticators to create and send a login request. - /// - internal abstract class BaseAuthenticator - { - // The logger. - private static readonly SFLogger logger = - SFLoggerFactory.GetLogger(); - - // The name of the authenticator. - protected string authName; - - // The session which created this authenticator. - protected SFSession session; - - // The client environment properties - protected LoginRequestClientEnv ClientEnv = SFEnvironment.ClientEnv; - - /// - /// The abstract base for all authenticators. - /// - /// The session which created the authenticator. - public BaseAuthenticator(SFSession session, string authName) - { - this.session = session; - this.authName = authName; - // Update the value for insecureMode because it can be different for each session - ClientEnv.insecureMode = session.properties[SFSessionProperty.INSECUREMODE]; - if (session.properties.TryGetValue(SFSessionProperty.APPLICATION, out var applicationName)) - { - // If an application name has been specified in the connection setting, use it - // Otherwise, it will default to the running process name - ClientEnv.application = applicationName; - } - } - - //// - protected async Task LoginAsync(CancellationToken cancellationToken) - { - var loginRequest = BuildLoginRequest(); - - var response = await session.restRequester.PostAsync(loginRequest, cancellationToken).ConfigureAwait(false); - - session.ProcessLoginResponse(response); - } - - /// - protected void Login() - { - var loginRequest = BuildLoginRequest(); - - var response = session.restRequester.Post(loginRequest); - - session.ProcessLoginResponse(response); - } - - /// - /// Specialized authenticator data to add to the login request. - /// - /// The login request data to update. - protected abstract void SetSpecializedAuthenticatorData(ref LoginRequestData data); - - /// - /// Builds a simple login request. Each authenticator will fill the Data part with their - /// specialized information. The common Data attributes are already filled (clientAppId, - /// ClienAppVersion...). - /// - /// A login request to send to the server. - private SFRestRequest BuildLoginRequest() - { - // build uri - var loginUrl = session.BuildLoginUrl(); - - LoginRequestData data = new LoginRequestData() - { - loginName = session.properties[SFSessionProperty.USER], - accountName = session.properties[SFSessionProperty.ACCOUNT], - clientAppId = SFEnvironment.DriverName, - clientAppVersion = SFEnvironment.DriverVersion, - clientEnv = ClientEnv, - SessionParameters = session.ParameterMap, - Authenticator = authName, - }; - - SetSpecializedAuthenticatorData(ref data); - - return session.BuildTimeoutRestRequest(loginUrl, new LoginRequest() { data = data }); - } - } - - /// - /// Authenticator Factory to build authenticators - /// - internal class AuthenticatorFactory - { - private static readonly SFLogger logger = SFLoggerFactory.GetLogger(); - /// - /// Generate the authenticator given the session - /// - /// session that requires the authentication - /// authenticator - /// when authenticator is unknown - internal static IAuthenticator GetAuthenticator(SFSession session) - { - string type = session.properties[SFSessionProperty.AUTHENTICATOR]; - if (type.Equals(BasicAuthenticator.AUTH_NAME, StringComparison.InvariantCultureIgnoreCase)) - { - return new BasicAuthenticator(session); - } - else if (type.Equals(ExternalBrowserAuthenticator.AUTH_NAME, StringComparison.InvariantCultureIgnoreCase)) - { - return new ExternalBrowserAuthenticator(session); - } - else if (type.Equals(KeyPairAuthenticator.AUTH_NAME, StringComparison.InvariantCultureIgnoreCase)) - { - // Get private key path or private key from connection settings - if (!session.properties.TryGetValue(SFSessionProperty.PRIVATE_KEY_FILE, out var pkPath) && - !session.properties.TryGetValue(SFSessionProperty.PRIVATE_KEY, out var pkContent)) - { - // There is no PRIVATE_KEY_FILE defined, can't authenticate with key-pair - string invalidStringDetail = - "Missing required PRIVATE_KEY_FILE or PRIVATE_KEY for key pair authentication"; - var error = new SnowflakeDbException( - SFError.INVALID_CONNECTION_STRING, - new object[] { invalidStringDetail }); - logger.Error(error.Message, error); - throw error; - } - - return new KeyPairAuthenticator(session); - } - else if (type.Equals(OAuthAuthenticator.AUTH_NAME, StringComparison.InvariantCultureIgnoreCase)) - { - // Get private key path or private key from connection settings - if (!session.properties.TryGetValue(SFSessionProperty.TOKEN, out var pkPath)) - { - // There is no TOKEN defined, can't authenticate with oauth - string invalidStringDetail = - "Missing required TOKEN for Oauth authentication"; - var error = new SnowflakeDbException( - SFError.INVALID_CONNECTION_STRING, - new object[] { invalidStringDetail }); - logger.Error(error.Message, error); - throw error; - } - - return new OAuthAuthenticator(session); - } - // Okta would provide a url of form: https://xxxxxx.okta.com or https://xxxxxx.oktapreview.com or https://vanity.url/snowflake/okta - else if (type.Contains("okta") && type.StartsWith("https://")) - { - return new OktaAuthenticator(session, type); - } - - var e = new SnowflakeDbException(SFError.UNKNOWN_AUTHENTICATOR, type); - - logger.Error("Unknown authenticator", e); - - throw e; - } - } } diff --git a/Snowflake.Data/Core/Authenticator/KeyPairAuthenticator.cs b/Snowflake.Data/Core/Authenticator/KeyPairAuthenticator.cs index fcfb70695..717a5d44d 100644 --- a/Snowflake.Data/Core/Authenticator/KeyPairAuthenticator.cs +++ b/Snowflake.Data/Core/Authenticator/KeyPairAuthenticator.cs @@ -19,6 +19,8 @@ using Org.BouncyCastle.X509; using System.Security.Claims; using Microsoft.IdentityModel.Tokens; +using Snowflake.Data.Core.Session; + namespace Snowflake.Data.Core.Authenticator { /// @@ -46,7 +48,7 @@ class KeyPairAuthenticator : BaseAuthenticator, IAuthenticator /// Session which created this authenticator internal KeyPairAuthenticator(SFSession session) : base(session, AUTH_NAME) { - this.session = session; + this.Session = session; this.rsaProvider = new RSACryptoServiceProvider(); } @@ -86,10 +88,10 @@ private string GenerateJwtToken() logger.Info("Key-pair Authentication"); bool hasPkPath = - session.properties.TryGetValue(SFSessionProperty.PRIVATE_KEY_FILE, out var pkPath); + Session.properties.TryGetValue(SFSessionProperty.PRIVATE_KEY_FILE, out var pkPath); bool hasPkContent = - session.properties.TryGetValue(SFSessionProperty.PRIVATE_KEY, out var pkContent); - session.properties.TryGetValue(SFSessionProperty.PRIVATE_KEY_PWD, out var pkPwd); + Session.properties.TryGetValue(SFSessionProperty.PRIVATE_KEY, out var pkContent); + Session.properties.TryGetValue(SFSessionProperty.PRIVATE_KEY_PWD, out var pkPwd); // Extract the public key from the private key to generate the fingerprints RSAParameters rsaParams; @@ -169,9 +171,9 @@ private string GenerateJwtToken() * Note : Lifetime = 120sec for Python impl, 60sec for Jdbc and Odbc */ String accountUser = - session.properties[SFSessionProperty.ACCOUNT].ToUpper() + + Session.properties[SFSessionProperty.ACCOUNT].ToUpper() + "." + - session.properties[SFSessionProperty.USER].ToUpper(); + Session.properties[SFSessionProperty.USER].ToUpper(); String issuer = accountUser + "." + publicKeyFingerPrint; var claims = new[] { new Claim( diff --git a/Snowflake.Data/Core/Authenticator/OAuthAuthenticator.cs b/Snowflake.Data/Core/Authenticator/OAuthAuthenticator.cs index 5e8f4a310..aa32b6775 100644 --- a/Snowflake.Data/Core/Authenticator/OAuthAuthenticator.cs +++ b/Snowflake.Data/Core/Authenticator/OAuthAuthenticator.cs @@ -4,6 +4,7 @@ using System.Text; using System.Threading; using System.Threading.Tasks; +using Snowflake.Data.Core.Session; namespace Snowflake.Data.Core.Authenticator { @@ -26,7 +27,7 @@ class OAuthAuthenticator : BaseAuthenticator, IAuthenticator /// Session which created this authenticator internal OAuthAuthenticator(SFSession session) : base(session, AUTH_NAME) { - this.session = session; + this.Session = session; } /// @@ -45,7 +46,7 @@ async public Task AuthenticateAsync(CancellationToken cancellationToken) protected override void SetSpecializedAuthenticatorData(ref LoginRequestData data) { // Add the token to the Data attribute - data.Token = session.properties[SFSessionProperty.TOKEN]; + data.Token = Session.properties[SFSessionProperty.TOKEN]; // Remove the login name for an OAuth session data.loginName = ""; } diff --git a/Snowflake.Data/Core/Authenticator/Okta/IIdpTokenRestRequestFactory.cs b/Snowflake.Data/Core/Authenticator/Okta/IIdpTokenRestRequestFactory.cs new file mode 100644 index 000000000..f15005319 --- /dev/null +++ b/Snowflake.Data/Core/Authenticator/Okta/IIdpTokenRestRequestFactory.cs @@ -0,0 +1,11 @@ +using System; +using Snowflake.Data.Core.Authenticator.Okta.Models; +using Snowflake.Data.Core.Session; + +namespace Snowflake.Data.Core.Authenticator.Okta +{ + internal interface IIdpTokenRestRequestFactory + { + IdpTokenRestRequest Create(Uri tokenUrl, SFSession session); + } +} \ No newline at end of file diff --git a/Snowflake.Data/Core/Authenticator/Okta/ISamlRestRequestFactory.cs b/Snowflake.Data/Core/Authenticator/Okta/ISamlRestRequestFactory.cs new file mode 100644 index 000000000..7713550bd --- /dev/null +++ b/Snowflake.Data/Core/Authenticator/Okta/ISamlRestRequestFactory.cs @@ -0,0 +1,10 @@ +using System; +using Snowflake.Data.Core.Authenticator.Okta.Models; + +namespace Snowflake.Data.Core.Authenticator.Okta +{ + internal interface ISamlRestRequestFactory + { + SamlRestRequest Create(Uri ssoUrl, string onetimeToken, TimeSpan timeout); + } +} \ No newline at end of file diff --git a/Snowflake.Data/Core/Authenticator/Okta/IdpTokenRestRequestFactory.cs b/Snowflake.Data/Core/Authenticator/Okta/IdpTokenRestRequestFactory.cs new file mode 100644 index 000000000..3426a35bc --- /dev/null +++ b/Snowflake.Data/Core/Authenticator/Okta/IdpTokenRestRequestFactory.cs @@ -0,0 +1,26 @@ +using System; +using Snowflake.Data.Core.Authenticator.Okta.Models; +using Snowflake.Data.Core.Session; + +namespace Snowflake.Data.Core.Authenticator.Okta +{ + internal class IdpTokenRestRequestFactory : IIdpTokenRestRequestFactory + { + private readonly TimeSpan _httpTimeout = TimeSpan.FromSeconds(16); + + public IdpTokenRestRequest Create(Uri tokenUrl, SFSession session) + { + return new IdpTokenRestRequest() + { + Url = tokenUrl, + RestTimeout = session.connectionTimeout, + HttpTimeout = _httpTimeout, + JsonBody = new IdpTokenRequest() + { + Username = session.properties[SFSessionProperty.USER], + Password = session.properties[SFSessionProperty.PASSWORD], + }, + }; + } + } +} \ No newline at end of file diff --git a/Snowflake.Data/Core/Authenticator/Okta/Models/IdpTokenRequest.cs b/Snowflake.Data/Core/Authenticator/Okta/Models/IdpTokenRequest.cs new file mode 100644 index 000000000..4f1c1f7dc --- /dev/null +++ b/Snowflake.Data/Core/Authenticator/Okta/Models/IdpTokenRequest.cs @@ -0,0 +1,13 @@ +using Newtonsoft.Json; + +namespace Snowflake.Data.Core.Authenticator.Okta.Models +{ + internal class IdpTokenRequest + { + [JsonProperty(PropertyName = "username")] + internal string Username { get; set; } + + [JsonProperty(PropertyName = "password")] + internal string Password { get; set; } + } +} \ No newline at end of file diff --git a/Snowflake.Data/Core/Authenticator/Okta/Models/IdpTokenResponse.cs b/Snowflake.Data/Core/Authenticator/Okta/Models/IdpTokenResponse.cs new file mode 100644 index 000000000..4c28bcbb1 --- /dev/null +++ b/Snowflake.Data/Core/Authenticator/Okta/Models/IdpTokenResponse.cs @@ -0,0 +1,12 @@ +using Newtonsoft.Json; + +namespace Snowflake.Data.Core.Authenticator.Okta.Models +{ + internal class IdpTokenResponse + { + [JsonProperty(PropertyName = "cookieToken")] + internal string CookieToken { get; set; } + [JsonProperty(PropertyName = "sessionToken")] + internal string SessionToken { get; set; } + } +} \ No newline at end of file diff --git a/Snowflake.Data/Core/Authenticator/Okta/Models/IdpTokenRestRequest.cs b/Snowflake.Data/Core/Authenticator/Okta/Models/IdpTokenRestRequest.cs new file mode 100644 index 000000000..88ebecac6 --- /dev/null +++ b/Snowflake.Data/Core/Authenticator/Okta/Models/IdpTokenRestRequest.cs @@ -0,0 +1,25 @@ +using System.Net.Http; +using System.Net.Http.Headers; +using System.Text; +using Newtonsoft.Json; + +namespace Snowflake.Data.Core.Authenticator.Okta.Models +{ + internal class IdpTokenRestRequest : BaseRestRequest, IRestRequest + { + private static readonly MediaTypeWithQualityHeaderValue JsonHeader = new MediaTypeWithQualityHeaderValue("application/json"); + + internal IdpTokenRequest JsonBody { get; set; } + + HttpRequestMessage IRestRequest.ToRequestMessage(HttpMethod method) + { + var message = newMessage(method, Url); + message.Headers.Accept.Add(JsonHeader); + + var json = JsonConvert.SerializeObject(JsonBody, JsonUtils.JsonSettings); + message.Content = new StringContent(json, Encoding.UTF8, "application/json"); + + return message; + } + } +} \ No newline at end of file diff --git a/Snowflake.Data/Core/Authenticator/Okta/Models/SamlRestRequest.cs b/Snowflake.Data/Core/Authenticator/Okta/Models/SamlRestRequest.cs new file mode 100644 index 000000000..fa8880449 --- /dev/null +++ b/Snowflake.Data/Core/Authenticator/Okta/Models/SamlRestRequest.cs @@ -0,0 +1,24 @@ +using System; +using System.Net.Http; +using System.Net.Http.Headers; + +namespace Snowflake.Data.Core.Authenticator.Okta.Models +{ + internal class SamlRestRequest : BaseRestRequest, IRestRequest + { + internal string OnetimeToken { set; get; } + + HttpRequestMessage IRestRequest.ToRequestMessage(HttpMethod method) + { + var builder = new UriBuilder(Url) + { + Query = "RelayState=%2Fsome%2Fdeep%2Flink&onetimetoken=" + OnetimeToken + }; + var message = newMessage(method, builder.Uri); + + message.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("*/*")); + + return message; + } + } +} \ No newline at end of file diff --git a/Snowflake.Data/Core/Authenticator/Okta/OktaAuthenticator.cs b/Snowflake.Data/Core/Authenticator/Okta/OktaAuthenticator.cs new file mode 100644 index 000000000..5c85376a9 --- /dev/null +++ b/Snowflake.Data/Core/Authenticator/Okta/OktaAuthenticator.cs @@ -0,0 +1,152 @@ +/* + * Copyright (c) 2012-2021 Snowflake Computing Inc. All rights reserved. + */ + +using System; +using System.Threading; +using System.Threading.Tasks; +using System.Web; +using Snowflake.Data.Client; +using Snowflake.Data.Core.Authenticator.Okta.Models; +using Snowflake.Data.Core.Session; +using Snowflake.Data.Log; + +namespace Snowflake.Data.Core.Authenticator.Okta +{ + /// + /// OktaAuthenticator would perform several steps of authentication with Snowflake and Okta idp + /// + internal class OktaAuthenticator : BaseAuthenticator, IAuthenticator + { + private readonly ISamlRestRequestFactory _samlRestRequestFactory; + private readonly IIdpTokenRestRequestFactory _idpTokenRestRequestFactory; + private static readonly SFLogger s_logger = SFLoggerFactory.GetLogger(); + + /// + /// url of the okta idp + /// + private readonly Uri _oktaUrl; + + // The raw Saml token. + private string _samlRawHtmlString; + + /// + /// Constructor of the Okta authenticator + /// + /// + /// + /// + /// + internal OktaAuthenticator(SFSession session, string oktaUriString, ISamlRestRequestFactory samlRestRequestFactory, IIdpTokenRestRequestFactory idpTokenRestRequestFactory) : + base(session, oktaUriString) + { + _samlRestRequestFactory = samlRestRequestFactory; + _idpTokenRestRequestFactory = idpTokenRestRequestFactory; + _oktaUrl = new Uri(oktaUriString); + } + + /// + public async Task AuthenticateAsync(CancellationToken cancellationToken) + { + s_logger.Info("Okta Authentication"); + + s_logger.Debug("step 1: get sso and token url"); + var authenticatorRestRequest = BuildAuthenticatorRestRequest(); + var authenticatorResponse = await Session.restRequester.PostAsync(authenticatorRestRequest, cancellationToken); + authenticatorResponse.FilterFailedResponse(); + var ssoUrl = new Uri(authenticatorResponse.data.ssoUrl); + var tokenUrl = new Uri(authenticatorResponse.data.tokenUrl); + + s_logger.Debug("step 2: verify urls fetched from step 1"); + s_logger.Debug("Checking sso url"); + VerifyUrls(ssoUrl, _oktaUrl); + s_logger.Debug("Checking token url"); + VerifyUrls(tokenUrl, _oktaUrl); + + s_logger.Debug("step 3: get idp onetime token"); + var idpTokenRestRequest = _idpTokenRestRequestFactory.Create(tokenUrl, Session); + var idpResponse = await Session.restRequester.PostAsync(idpTokenRestRequest, cancellationToken); + var onetimeToken = idpResponse.SessionToken ?? idpResponse.CookieToken; + + s_logger.Debug("step 4: get SAML response from sso"); + var samlRestRequest = _samlRestRequestFactory.Create(ssoUrl, onetimeToken, Session.connectionTimeout); + using (var samlRawResponse = await Session.restRequester.GetAsync(samlRestRequest, cancellationToken)) + { + _samlRawHtmlString = await samlRawResponse.Content.ReadAsStringAsync(cancellationToken); + } + + s_logger.Debug("step 5: verify postback url in SAML response"); + VerifyPostbackUrl(); + + s_logger.Debug("step 6: send SAML response to snowflake to login"); + await LoginAsync(cancellationToken); + } + + void IAuthenticator.Authenticate() + { + AuthenticateAsync(CancellationToken.None).Wait(); + } + + private SFRestRequest BuildAuthenticatorRestRequest() + { + var fedUrl = Session.BuildUri(RestPath.SF_AUTHENTICATOR_REQUEST_PATH); + var data = new AuthenticatorRequestData() + { + AccountName = Session.properties[SFSessionProperty.ACCOUNT], + Authenticator = _oktaUrl.ToString(), + DriverVersion = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString(), + DriverName = ".NET" + }; + + return Session.BuildTimeoutRestRequest(fedUrl, new AuthenticatorRequest() { Data = data }); + } + + /// + protected override void SetSpecializedAuthenticatorData(ref LoginRequestData data) + { + data.RawSamlResponse = _samlRawHtmlString; + } + + private void VerifyUrls(Uri tokenOrSsoUrl, Uri sessionUrl) + { + if (tokenOrSsoUrl.Scheme != sessionUrl.Scheme || tokenOrSsoUrl.Host != sessionUrl.Host) + { + var e = new SnowflakeDbException( + SFError.IDP_SSO_TOKEN_URL_MISMATCH, tokenOrSsoUrl.ToString(), _oktaUrl.ToString()); + s_logger.Error("Different urls", e); + throw e; + } + } + + private void VerifyPostbackUrl() + { + var formIndex = _samlRawHtmlString.IndexOf(" - /// OktaAuthenticator would perform serveral steps of authentication with Snowflake and Okta idp - /// - class OktaAuthenticator : BaseAuthenticator, IAuthenticator - { - private static readonly SFLogger logger = SFLoggerFactory.GetLogger(); - - /// - /// url of the okta idp - /// - private Uri oktaUrl; - - // The raw Saml token. - private string samlRawHtmlString; - - /// - /// Constructor of the Okta authenticator - /// - /// - /// - internal OktaAuthenticator(SFSession session, string oktaUriString) : - base(session, oktaUriString) - { - oktaUrl = new Uri(oktaUriString); - } - - /// - async Task IAuthenticator.AuthenticateAsync(CancellationToken cancellationToken) - { - logger.Info("Okta Authentication"); - - logger.Debug("step 1: get sso and token url"); - var authenticatorRestRequest = BuildAuthenticatorRestRequest(); - var authenticatorResponse = await session.restRequester.PostAsync(authenticatorRestRequest, cancellationToken).ConfigureAwait(false); - authenticatorResponse.FilterFailedResponse(); - Uri ssoUrl = new Uri(authenticatorResponse.data.ssoUrl); - Uri tokenUrl = new Uri(authenticatorResponse.data.tokenUrl); - - logger.Debug("step 2: verify urls fetched from step 1"); - logger.Debug("Checking sso url"); - VerifyUrls(ssoUrl, oktaUrl); - logger.Debug("Checking token url"); - VerifyUrls(tokenUrl, oktaUrl); - - logger.Debug("step 3: get idp onetime token"); - IdpTokenRestRequest idpTokenRestRequest = BuildIdpTokenRestRequest(tokenUrl); - var idpResponse = await session.restRequester.PostAsync(idpTokenRestRequest, cancellationToken).ConfigureAwait(false); - string onetimeToken = idpResponse.SessionToken != null ? idpResponse.SessionToken : idpResponse.CookieToken; - - logger.Debug("step 4: get SAML reponse from sso"); - var samlRestRequest = BuildSAMLRestRequest(ssoUrl, onetimeToken); - using (var samlRawResponse = await session.restRequester.GetAsync(samlRestRequest, cancellationToken).ConfigureAwait(false)) - { - samlRawHtmlString = await samlRawResponse.Content.ReadAsStringAsync().ConfigureAwait(false); - } - - logger.Debug("step 5: verify postback url in SAML reponse"); - VerifyPostbackUrl(); - - logger.Debug("step 6: send SAML reponse to snowflake to login"); - await base.LoginAsync(cancellationToken).ConfigureAwait(false); - } - - void IAuthenticator.Authenticate() - { - logger.Info("Okta Authentication"); - - logger.Debug("step 1: get sso and token url"); - var authenticatorRestRequest = BuildAuthenticatorRestRequest(); - var authenticatorResponse = session.restRequester.Post(authenticatorRestRequest); - authenticatorResponse.FilterFailedResponse(); - Uri ssoUrl = new Uri(authenticatorResponse.data.ssoUrl); - Uri tokenUrl = new Uri(authenticatorResponse.data.tokenUrl); - - logger.Debug("step 2: verify urls fetched from step 1"); - logger.Debug("Checking sso url"); - VerifyUrls(ssoUrl, oktaUrl); - logger.Debug("Checking token url"); - VerifyUrls(tokenUrl, oktaUrl); - - logger.Debug("step 3: get idp onetime token"); - IdpTokenRestRequest idpTokenRestRequest = BuildIdpTokenRestRequest(tokenUrl); - var idpResponse = session.restRequester.Post(idpTokenRestRequest); - string onetimeToken = idpResponse.SessionToken != null ? idpResponse.SessionToken : idpResponse.CookieToken; - - logger.Debug("step 4: get SAML reponse from sso"); - var samlRestRequest = BuildSAMLRestRequest(ssoUrl, onetimeToken); - using (var samlRawResponse = session.restRequester.Get(samlRestRequest)) - { - samlRawHtmlString = Task.Run(async () => await samlRawResponse.Content.ReadAsStringAsync().ConfigureAwait(false)).Result; - } - - logger.Debug("step 5: verify postback url in SAML reponse"); - VerifyPostbackUrl(); - - logger.Debug("step 6: send SAML reponse to snowflake to login"); - base.Login(); - } - - private SFRestRequest BuildAuthenticatorRestRequest() - { - var fedUrl = session.BuildUri(RestPath.SF_AUTHENTICATOR_REQUEST_PATH); - var data = new AuthenticatorRequestData() - { - AccountName = session.properties[SFSessionProperty.ACCOUNT], - Authenticator = oktaUrl.ToString(), - DriverVersion = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString(), - DriverName = ".NET" - }; - - int connectionTimeoutSec = int.Parse(session.properties[SFSessionProperty.CONNECTION_TIMEOUT]); - - return session.BuildTimeoutRestRequest(fedUrl, new AuthenticatorRequest() { Data = data }); - } - - private IdpTokenRestRequest BuildIdpTokenRestRequest(Uri tokenUrl) - { - return new IdpTokenRestRequest() - { - Url = tokenUrl, - RestTimeout = session.connectionTimeout, - HttpTimeout = TimeSpan.FromSeconds(16), - JsonBody = new IdpTokenRequest() - { - Username = session.properties[SFSessionProperty.USER], - Password = session.properties[SFSessionProperty.PASSWORD], - }, - }; - } - - private SAMLRestRequest BuildSAMLRestRequest(Uri ssoUrl, string onetimeToken) - { - return new SAMLRestRequest() - { - Url = ssoUrl, - RestTimeout = session.connectionTimeout, - HttpTimeout = Timeout.InfiniteTimeSpan, - OnetimeToken = onetimeToken, - }; - } - - /// - protected override void SetSpecializedAuthenticatorData(ref LoginRequestData data) - { - data.RawSamlResponse = samlRawHtmlString; - } - - private void VerifyUrls(Uri tokenOrSsoUrl, Uri sessionUrl) - { - if (tokenOrSsoUrl.Scheme != sessionUrl.Scheme || tokenOrSsoUrl.Host != sessionUrl.Host) - { - var e = new SnowflakeDbException( - SFError.IDP_SSO_TOKEN_URL_MISMATCH, tokenOrSsoUrl.ToString(), oktaUrl.ToString()); - logger.Error("Different urls", e); - throw e; - } - } - - private void VerifyPostbackUrl() - { - int formIndex = samlRawHtmlString.IndexOf(" /// The status of the file to be uploaded/downloaded. diff --git a/Snowflake.Data/Core/FileTransfer/StorageClient/ISFRemoteStorageClient.cs b/Snowflake.Data/Core/FileTransfer/StorageClient/ISFRemoteStorageClient.cs index b20907d9a..cf2b9c82a 100644 --- a/Snowflake.Data/Core/FileTransfer/StorageClient/ISFRemoteStorageClient.cs +++ b/Snowflake.Data/Core/FileTransfer/StorageClient/ISFRemoteStorageClient.cs @@ -2,12 +2,11 @@ * Copyright (c) 2012-2023 Snowflake Computing Inc. All rights reserved. */ -using System; using System.IO; using System.Threading; using System.Threading.Tasks; -namespace Snowflake.Data.Core.FileTransfer +namespace Snowflake.Data.Core.FileTransfer.StorageClient { internal class WrappedContentInfo { diff --git a/Snowflake.Data/Core/FileTransfer/StorageClient/SFLocalStorageUtil.cs b/Snowflake.Data/Core/FileTransfer/StorageClient/SFLocalStorageUtil.cs index 6b98f9fb1..a622797b3 100644 --- a/Snowflake.Data/Core/FileTransfer/StorageClient/SFLocalStorageUtil.cs +++ b/Snowflake.Data/Core/FileTransfer/StorageClient/SFLocalStorageUtil.cs @@ -4,7 +4,7 @@ using System.IO; -namespace Snowflake.Data.Core.FileTransfer +namespace Snowflake.Data.Core.FileTransfer.StorageClient { /// /// The storage client for local upload/download. diff --git a/Snowflake.Data/Core/FileTransfer/StorageClient/SFRemoteStorageUtil.cs b/Snowflake.Data/Core/FileTransfer/StorageClient/SFRemoteStorageUtil.cs index 92e8dd467..b9677a589 100644 --- a/Snowflake.Data/Core/FileTransfer/StorageClient/SFRemoteStorageUtil.cs +++ b/Snowflake.Data/Core/FileTransfer/StorageClient/SFRemoteStorageUtil.cs @@ -2,13 +2,12 @@ * Copyright (c) 2012-2019 Snowflake Computing Inc. All rights reserved. */ -using Snowflake.Data.Core.FileTransfer.StorageClient; using System; using System.IO; using System.Threading; using System.Threading.Tasks; -namespace Snowflake.Data.Core.FileTransfer +namespace Snowflake.Data.Core.FileTransfer.StorageClient { /// /// The class containing file header information. diff --git a/Snowflake.Data/Core/FileTransfer/StorageClient/SFS3Client.cs b/Snowflake.Data/Core/FileTransfer/StorageClient/SFS3Client.cs index e68fbbd3e..244881622 100644 --- a/Snowflake.Data/Core/FileTransfer/StorageClient/SFS3Client.cs +++ b/Snowflake.Data/Core/FileTransfer/StorageClient/SFS3Client.cs @@ -20,19 +20,6 @@ namespace Snowflake.Data.Core.FileTransfer.StorageClient /// class SFS3Client : ISFRemoteStorageClient { - /// - /// The metadata of the S3 file. - /// - internal class S3Metadata - { - public string HTTP_HEADER_CONTENT_TYPE { get; set; } - public string SFC_DIGEST { get; set; } - public string AMZ_IV { get; set; } - public string AMZ_KEY { get; set; } - public string AMZ_MATDESC { get; set; } - - } - /// /// The metadata header keys. /// diff --git a/Snowflake.Data/Core/HeartBeatBackground.cs b/Snowflake.Data/Core/HeartBeatBackground.cs index f8a042ac3..b45663189 100644 --- a/Snowflake.Data/Core/HeartBeatBackground.cs +++ b/Snowflake.Data/Core/HeartBeatBackground.cs @@ -5,6 +5,7 @@ using System.Threading; using System.Threading.Tasks; using Snowflake.Data.Client; +using Snowflake.Data.Core.Session; namespace Snowflake.Data.Core { diff --git a/Snowflake.Data/Core/RestRequest.cs b/Snowflake.Data/Core/RestRequest.cs index bc4ec8d21..54feee81b 100644 --- a/Snowflake.Data/Core/RestRequest.cs +++ b/Snowflake.Data/Core/RestRequest.cs @@ -8,6 +8,7 @@ using System.Text; using System.Collections.Generic; using Newtonsoft.Json; +using Snowflake.Data.Core.Session; namespace Snowflake.Data.Core { @@ -15,7 +16,7 @@ internal interface IRestRequest { HttpRequestMessage ToRequestMessage(HttpMethod method); TimeSpan GetRestTimeout(); - string getSid(); + string GetSid(); } /// @@ -62,7 +63,7 @@ TimeSpan IRestRequest.GetRestTimeout() return RestTimeout; } - string IRestRequest.getSid() + string IRestRequest.GetSid() { return sid; } diff --git a/Snowflake.Data/Core/RestRequester.cs b/Snowflake.Data/Core/RestRequester.cs index e9064495d..0ddeca0d5 100644 --- a/Snowflake.Data/Core/RestRequester.cs +++ b/Snowflake.Data/Core/RestRequester.cs @@ -94,7 +94,7 @@ private async Task SendAsync(HttpMethod method, CancellationToken externalCancellationToken) { HttpRequestMessage message = request.ToRequestMessage(method); - return await SendAsync(message, request.GetRestTimeout(), externalCancellationToken, request.getSid()).ConfigureAwait(false); + return await SendAsync(message, request.GetRestTimeout(), externalCancellationToken, request.GetSid()).ConfigureAwait(false); } protected virtual async Task SendAsync(HttpRequestMessage message, diff --git a/Snowflake.Data/Core/SFBindUploader.cs b/Snowflake.Data/Core/SFBindUploader.cs index 56cd376bd..8cf6a253c 100644 --- a/Snowflake.Data/Core/SFBindUploader.cs +++ b/Snowflake.Data/Core/SFBindUploader.cs @@ -6,6 +6,7 @@ using System.Text; using System.Threading; using System.Threading.Tasks; +using Snowflake.Data.Core.Session; using Snowflake.Data.Log; namespace Snowflake.Data.Core diff --git a/Snowflake.Data/Core/SFBlockingChunkDownloader.cs b/Snowflake.Data/Core/SFBlockingChunkDownloader.cs index b3dae7928..b79af6860 100755 --- a/Snowflake.Data/Core/SFBlockingChunkDownloader.cs +++ b/Snowflake.Data/Core/SFBlockingChunkDownloader.cs @@ -11,6 +11,7 @@ using System.Text; using System.Threading; using System.Threading.Tasks; +using Snowflake.Data.Core.Session; using Snowflake.Data.Log; namespace Snowflake.Data.Core diff --git a/Snowflake.Data/Core/SFBlockingChunkDownloaderV3.cs b/Snowflake.Data/Core/SFBlockingChunkDownloaderV3.cs index 33451a0da..ce6789cd0 100755 --- a/Snowflake.Data/Core/SFBlockingChunkDownloaderV3.cs +++ b/Snowflake.Data/Core/SFBlockingChunkDownloaderV3.cs @@ -16,6 +16,7 @@ using Newtonsoft.Json; using System.Diagnostics; using Newtonsoft.Json.Serialization; +using Snowflake.Data.Core.Session; using Snowflake.Data.Log; namespace Snowflake.Data.Core diff --git a/Snowflake.Data/Core/SFMultiStatementsResultSet.cs b/Snowflake.Data/Core/SFMultiStatementsResultSet.cs index c811deb8b..c2ad642af 100644 --- a/Snowflake.Data/Core/SFMultiStatementsResultSet.cs +++ b/Snowflake.Data/Core/SFMultiStatementsResultSet.cs @@ -8,6 +8,7 @@ using Snowflake.Data.Log; using Snowflake.Data.Client; using System.Collections.Generic; +using Snowflake.Data.Core.Session; namespace Snowflake.Data.Core { diff --git a/Snowflake.Data/Core/SFResultSet.cs b/Snowflake.Data/Core/SFResultSet.cs index 55b069806..e7ea0ff44 100755 --- a/Snowflake.Data/Core/SFResultSet.cs +++ b/Snowflake.Data/Core/SFResultSet.cs @@ -9,6 +9,7 @@ using Snowflake.Data.Client; using System.Collections.Generic; using System.Diagnostics; +using Snowflake.Data.Core.Session; namespace Snowflake.Data.Core { diff --git a/Snowflake.Data/Core/SFResultSetMetaData.cs b/Snowflake.Data/Core/SFResultSetMetaData.cs index 4a8c5651c..b24480f5a 100755 --- a/Snowflake.Data/Core/SFResultSetMetaData.cs +++ b/Snowflake.Data/Core/SFResultSetMetaData.cs @@ -7,6 +7,7 @@ using System.Data; using Snowflake.Data.Log; using Snowflake.Data.Client; +using Snowflake.Data.Core.Session; namespace Snowflake.Data.Core { diff --git a/Snowflake.Data/Core/SFStatement.cs b/Snowflake.Data/Core/SFStatement.cs index 3c48688ee..9372ec3ee 100644 --- a/Snowflake.Data/Core/SFStatement.cs +++ b/Snowflake.Data/Core/SFStatement.cs @@ -3,8 +3,6 @@ */ using System; -using System.Web; -using Newtonsoft.Json.Linq; using System.Collections.Generic; using System.IO; using System.Linq; @@ -14,6 +12,7 @@ using System.Threading; using System.Threading.Tasks; using System.Text; +using Snowflake.Data.Core.Session; namespace Snowflake.Data.Core { diff --git a/Snowflake.Data/Core/Session/EasyLoggingStarter.cs b/Snowflake.Data/Core/Session/EasyLoggingStarter.cs index 9800e5186..04066f416 100644 --- a/Snowflake.Data/Core/Session/EasyLoggingStarter.cs +++ b/Snowflake.Data/Core/Session/EasyLoggingStarter.cs @@ -7,7 +7,7 @@ using Snowflake.Data.Core.Tools; using Snowflake.Data.Log; -namespace Snowflake.Data.Core +namespace Snowflake.Data.Core.Session { internal class EasyLoggingStarter { diff --git a/Snowflake.Data/Core/Session/SFSession.cs b/Snowflake.Data/Core/Session/SFSession.cs index 2ad440407..d6115bbdb 100755 --- a/Snowflake.Data/Core/Session/SFSession.cs +++ b/Snowflake.Data/Core/Session/SFSession.cs @@ -4,20 +4,18 @@ using System; using System.Collections.Generic; -using System.IO; using System.Linq; +using System.Net.Http; using System.Security; +using System.Text.RegularExpressions; +using System.Threading; +using System.Threading.Tasks; using System.Web; -using Snowflake.Data.Log; using Snowflake.Data.Client; using Snowflake.Data.Core.Authenticator; -using System.Threading; -using System.Threading.Tasks; -using System.Net.Http; -using System.Text.RegularExpressions; -using Snowflake.Data.Configuration; +using Snowflake.Data.Log; -namespace Snowflake.Data.Core +namespace Snowflake.Data.Core.Session { public class SFSession { @@ -55,29 +53,29 @@ public class SFSession internal bool InsecureMode; - internal bool isHeartBeatEnabled; + private bool _isHeartBeatEnabled; - private HttpClient _HttpClient; + private readonly HttpClient _httpClient; private string arrayBindStage = null; private int arrayBindStageThreshold = 0; - internal int masterValidityInSeconds = 0; - - internal static readonly SFSessionHttpClientProperties.Extractor propertiesExtractor = new SFSessionHttpClientProperties.Extractor( + private int masterValidityInSeconds = 0; + + private static readonly SFSessionHttpClientProperties.Extractor propertiesExtractor = new SFSessionHttpClientProperties.Extractor( new SFSessionHttpClientProxyProperties.Extractor()); private readonly EasyLoggingStarter _easyLoggingStarter = EasyLoggingStarter.Instance; private long _startTime = 0; - internal string connStr = null; + internal readonly string ConnStr = null; - private QueryContextCache _queryContextCache = new QueryContextCache(_defaultQueryContextCacheSize); + private readonly QueryContextCache _queryContextCache = new QueryContextCache(_defaultQueryContextCacheSize); private int _queryContextCacheSize = _defaultQueryContextCacheSize; - private bool _disableQueryContextCache = false; + private readonly bool _disableQueryContextCache = false; - internal bool _disableConsoleLogin; + internal readonly bool _disableConsoleLogin; internal void ProcessLoginResponse(LoginResponse authnResponse) { @@ -100,7 +98,7 @@ internal void ProcessLoginResponse(LoginResponse authnResponse) } else { - SnowflakeDbException e = new SnowflakeDbException + var e = new SnowflakeDbException (SnowflakeDbException.CONNECTION_FAILURE_SSTATE, authnResponse.code, authnResponse.message, @@ -116,14 +114,10 @@ internal void ProcessLoginResponse(LoginResponse authnResponse) internal Uri BuildLoginUrl() { var queryParams = new Dictionary(); - string warehouseValue; - string dbValue; - string schemaValue; - string roleName; - queryParams[RestParams.SF_QUERY_WAREHOUSE] = properties.TryGetValue(SFSessionProperty.WAREHOUSE, out warehouseValue) ? warehouseValue : ""; - queryParams[RestParams.SF_QUERY_DB] = properties.TryGetValue(SFSessionProperty.DB, out dbValue) ? dbValue : ""; - queryParams[RestParams.SF_QUERY_SCHEMA] = properties.TryGetValue(SFSessionProperty.SCHEMA, out schemaValue) ? schemaValue : ""; - queryParams[RestParams.SF_QUERY_ROLE] = properties.TryGetValue(SFSessionProperty.ROLE, out roleName) ? roleName : ""; + queryParams[RestParams.SF_QUERY_WAREHOUSE] = properties.TryGetValue(SFSessionProperty.WAREHOUSE, out var warehouseValue) ? warehouseValue : ""; + queryParams[RestParams.SF_QUERY_DB] = properties.TryGetValue(SFSessionProperty.DB, out var dbValue) ? dbValue : ""; + queryParams[RestParams.SF_QUERY_SCHEMA] = properties.TryGetValue(SFSessionProperty.SCHEMA, out var schemaValue) ? schemaValue : ""; + queryParams[RestParams.SF_QUERY_ROLE] = properties.TryGetValue(SFSessionProperty.ROLE, out var roleName) ? roleName : ""; queryParams[RestParams.SF_QUERY_REQUEST_ID] = Guid.NewGuid().ToString(); queryParams[RestParams.SF_QUERY_REQUEST_GUID] = Guid.NewGuid().ToString(); @@ -136,19 +130,19 @@ internal Uri BuildLoginUrl() /// /// A string in the form of "key1=value1;key2=value2" internal SFSession( - String connectionString, + string connectionString, SecureString password) : this(connectionString, password, EasyLoggingStarter.Instance) { } internal SFSession( - String connectionString, + string connectionString, SecureString password, EasyLoggingStarter easyLoggingStarter) { _easyLoggingStarter = easyLoggingStarter; - connStr = connectionString; - properties = SFSessionProperties.parseConnectionString(connectionString, password); + ConnStr = connectionString; + properties = SFSessionProperties.ParseConnectionString(connectionString, password); _disableQueryContextCache = bool.Parse(properties[SFSessionProperty.DISABLEQUERYCONTEXTCACHE]); _disableConsoleLogin = bool.Parse(properties[SFSessionProperty.DISABLE_CONSOLE_LOGIN]); ValidateApplicationName(properties); @@ -158,8 +152,8 @@ internal SFSession( var httpClientConfig = extractedProperties.BuildHttpClientConfig(); ParameterMap = extractedProperties.ToParameterMap(); InsecureMode = extractedProperties.insecureMode; - _HttpClient = HttpUtil.Instance.GetHttpClient(httpClientConfig); - restRequester = new RestRequester(_HttpClient); + _httpClient = HttpUtil.Instance.GetHttpClient(httpClientConfig); + restRequester = new RestRequester(_httpClient); extractedProperties.CheckPropertiesAreValid(); connectionTimeout = extractedProperties.TimeoutDuration(); properties.TryGetValue(SFSessionProperty.CLIENT_CONFIG_FILE, out var easyLoggingConfigFile); @@ -193,7 +187,7 @@ private void ValidateApplicationName(SFSessionProperties properties) internal SFSession(String connectionString, SecureString password, IMockRestRequester restRequester) : this(connectionString, password) { // Inject the HttpClient to use with the Mock requester - restRequester.setHttpClient(_HttpClient); + restRequester.setHttpClient(_httpClient); // Override the Rest requester with the mock for testing this.restRequester = restRequester; } @@ -242,7 +236,7 @@ internal async Task OpenAsync(CancellationToken cancellationToken) await authenticator.AuthenticateAsync(cancellationToken).ConfigureAwait(false); } - internal void close() + internal void Close() { // Nothing to do if the session is not open if (!IsEstablished()) return; @@ -460,7 +454,7 @@ internal void UpdateDatabaseAndSchema(string databaseName, string schemaName) internal void startHeartBeatForThisSession() { - if (!this.isHeartBeatEnabled) + if (!this._isHeartBeatEnabled) { HeartBeatBackground heartBeatBg = HeartBeatBackground.Instance; if (this.masterValidityInSeconds == 0) @@ -470,16 +464,16 @@ internal void startHeartBeatForThisSession() this.masterValidityInSeconds = DEFAULT_TIMEOUT_IN_SECOND; } heartBeatBg.addConnection(this, this.masterValidityInSeconds); - this.isHeartBeatEnabled = true; + this._isHeartBeatEnabled = true; } } internal void stopHeartBeatForThisSession() { - if (this.isHeartBeatEnabled) + if (this._isHeartBeatEnabled) { HeartBeatBackground heartBeatBg = HeartBeatBackground.Instance; heartBeatBg.removeConnection(this); - this.isHeartBeatEnabled = false; + this._isHeartBeatEnabled = false; } } diff --git a/Snowflake.Data/Core/Session/SFSessionHttpClientProperties.cs b/Snowflake.Data/Core/Session/SFSessionHttpClientProperties.cs index f129de25a..7025d8e29 100644 --- a/Snowflake.Data/Core/Session/SFSessionHttpClientProperties.cs +++ b/Snowflake.Data/Core/Session/SFSessionHttpClientProperties.cs @@ -3,7 +3,7 @@ using System.Threading; using Snowflake.Data.Log; -namespace Snowflake.Data.Core +namespace Snowflake.Data.Core.Session { internal class SFSessionHttpClientProperties diff --git a/Snowflake.Data/Core/Session/SFSessionHttpClientProxyProperties.cs b/Snowflake.Data/Core/Session/SFSessionHttpClientProxyProperties.cs index 4266c585d..b7c927cde 100644 --- a/Snowflake.Data/Core/Session/SFSessionHttpClientProxyProperties.cs +++ b/Snowflake.Data/Core/Session/SFSessionHttpClientProxyProperties.cs @@ -1,7 +1,7 @@ using System; using System.Web; -namespace Snowflake.Data.Core +namespace Snowflake.Data.Core.Session { internal class SFSessionHttpClientProxyProperties diff --git a/Snowflake.Data/Core/Session/SFSessionParameter.cs b/Snowflake.Data/Core/Session/SFSessionParameter.cs index 97fdcec23..2bbfee1b5 100755 --- a/Snowflake.Data/Core/Session/SFSessionParameter.cs +++ b/Snowflake.Data/Core/Session/SFSessionParameter.cs @@ -2,7 +2,7 @@ * Copyright (c) 2012-2019 Snowflake Computing Inc. All rights reserved. */ -namespace Snowflake.Data.Core +namespace Snowflake.Data.Core.Session { internal enum SFSessionParameter { diff --git a/Snowflake.Data/Core/Session/SFSessionProperty.cs b/Snowflake.Data/Core/Session/SFSessionProperty.cs index 5953a7bbc..4beff0a36 100644 --- a/Snowflake.Data/Core/Session/SFSessionProperty.cs +++ b/Snowflake.Data/Core/Session/SFSessionProperty.cs @@ -4,16 +4,16 @@ using System; using System.Collections.Generic; +using System.Data.Common; +using System.Linq; using System.Net; using System.Security; -using Snowflake.Data.Log; +using System.Text.RegularExpressions; using Snowflake.Data.Client; using Snowflake.Data.Core.Authenticator; -using System.Data.Common; -using System.Linq; -using System.Text.RegularExpressions; +using Snowflake.Data.Log; -namespace Snowflake.Data.Core +namespace Snowflake.Data.Core.Session { internal enum SFSessionProperty { @@ -128,11 +128,11 @@ public override bool Equals(object obj) SFSessionProperties prop = (SFSessionProperties)obj; foreach (SFSessionProperty sessionProperty in Enum.GetValues(typeof(SFSessionProperty))) { - if (this.ContainsKey(sessionProperty) ^ prop.ContainsKey(sessionProperty)) + if (ContainsKey(sessionProperty) ^ prop.ContainsKey(sessionProperty)) { return false; } - if (!this.ContainsKey(sessionProperty)) + if (!ContainsKey(sessionProperty)) { continue; } @@ -155,7 +155,7 @@ public override int GetHashCode() return base.GetHashCode(); } - internal static SFSessionProperties parseConnectionString(String connectionString, SecureString password) + internal static SFSessionProperties ParseConnectionString(string connectionString, SecureString password) { logger.Info("Start parsing connection string."); DbConnectionStringBuilder builder = new DbConnectionStringBuilder(); @@ -170,10 +170,10 @@ internal static SFSessionProperties parseConnectionString(String connectionStrin SFError.INVALID_CONNECTION_STRING, e.Message); } - SFSessionProperties properties = new SFSessionProperties(); + var properties = new SFSessionProperties(); - string[] keys = new string[builder.Keys.Count]; - string[] values = new string[builder.Values.Count]; + var keys = new string[builder.Keys.Count]; + var values = new string[builder.Values.Count]; builder.Keys.CopyTo(keys, 0); builder.Values.CopyTo(values,0); diff --git a/Snowflake.Data/Core/Session/SessionPool.cs b/Snowflake.Data/Core/Session/SessionPool.cs index 14ad70848..643e01c93 100644 --- a/Snowflake.Data/Core/Session/SessionPool.cs +++ b/Snowflake.Data/Core/Session/SessionPool.cs @@ -57,7 +57,7 @@ private void CleanExpiredSessions() { if (item.IsExpired(_timeout, timeNow)) { - Task.Run(() => item.close()); + Task.Run(() => item.Close()); _sessions.Remove(item); } } @@ -89,14 +89,14 @@ private SFSession GetIdleSession(string connStr) { for (int i = 0; i < _sessions.Count; i++) { - if (_sessions[i].connStr.Equals(connStr)) + if (_sessions[i].ConnStr.Equals(connStr)) { SFSession session = _sessions[i]; _sessions.RemoveAt(i); long timeNow = DateTimeOffset.UtcNow.ToUnixTimeSeconds(); if (session.IsExpired(_timeout, timeNow)) { - Task.Run(() => session.close()); + Task.Run(() => session.Close()); i--; } else @@ -187,7 +187,7 @@ internal void ClearAllPools() { foreach (SFSession session in _sessions) { - session.close(); // it is left synchronously here because too much async tasks slows down testing + session.Close(); // it is left synchronously here because too much async tasks slows down testing } _sessions.Clear(); }