Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SNOW-1406763 Test special chars in password #943

Closed
wants to merge 38 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
af36804
pool/SNOW-902608 #2/4 new pool version v2 (#794)
sfc-gh-mhofman Nov 9, 2023
bf7a13e
pool/SNOW-937189 split pool tests (#815)
sfc-gh-knozderko Nov 20, 2023
56f0b81
Pool/SNOW-937189 busy sessions in pool (3/4) (#818)
sfc-gh-knozderko Nov 28, 2023
85204fc
SNOW-937190 Wait for idle sessions available (#840)
sfc-gh-knozderko Jan 29, 2024
052d895
SNOW-902632 connection string driven pool config (#873)
sfc-gh-knozderko Mar 25, 2024
0983d94
Pool/snow-902610 min pool size (#880)
sfc-gh-knozderko Apr 3, 2024
b842cbd
Fix flaky test TestWaitUntilResourceAvailable (#907)
sfc-gh-knozderko Apr 8, 2024
7db9d54
Pool/SNOW-937183 Prevent evicted connections from returning to the po…
sfc-gh-knozderko Apr 12, 2024
5a3c451
Merge branch 'master' into pool/SNOW-860872-connection-pool
sfc-gh-knozderko Apr 18, 2024
43d8fd4
Merge branch 'master' into pool/SNOW-860872-connection-pool
sfc-gh-knozderko Apr 23, 2024
4f2a167
SNOW-1344341 make new pool as a default one (#931)
sfc-gh-knozderko Apr 26, 2024
e727d1a
SNOW-937188 pool mode where a session gets destroyed on pooling when …
sfc-gh-mhofman Apr 26, 2024
afe21b9
SNOW-1353952 GetPool interface driven with user/password
sfc-gh-mhofman Apr 29, 2024
e84b33c
SNOW-937188 review fixes
sfc-gh-mhofman Apr 29, 2024
0429a48
Merge branch 'pool/SNOW-1353952-getpool_interface' into pool/SNOW-937…
sfc-gh-mhofman Apr 29, 2024
5e4ef69
SNOW-937188 introduction of full API for new pool
sfc-gh-mhofman Apr 29, 2024
7a9d811
SNOW-937188 changed default of ChangedSession flag, changes to public…
sfc-gh-mhofman Apr 30, 2024
a77e6e8
SNOW-937188 adoption of new pool interfaces among tests
sfc-gh-mhofman Apr 30, 2024
98dd1f9
SNOW-937188 adoption of new pool interfaces among tests
sfc-gh-mhofman Apr 30, 2024
fdc027f
SNOW-937188 review suggestions
sfc-gh-mhofman May 6, 2024
5de53f9
SNOW-986233 Log pool status (#936)
sfc-gh-knozderko May 7, 2024
3ac0204
Merge branch 'pool/SNOW-860872-connection-pool' into pool/SNOW-937188…
sfc-gh-mhofman May 7, 2024
59013fa
make build work again
sfc-gh-knozderko May 7, 2024
a73b38d
fix review comments
sfc-gh-knozderko May 7, 2024
2849369
SNOW-937188 fixes to the unquoting and comparison of final session re…
sfc-gh-mhofman May 7, 2024
d705c21
SNOW-937188 fixes to the unquoting
sfc-gh-mhofman May 7, 2024
3cad13b
SNOW-937188 fixes to the unquoting
sfc-gh-mhofman May 7, 2024
6d6cc81
throw error when getting pool for invalid connection string
sfc-gh-knozderko May 7, 2024
6468c82
remove test for pool identification for invalid connection string
sfc-gh-knozderko May 8, 2024
459ead6
fix issues
sfc-gh-knozderko May 8, 2024
ca5efb5
SNOW-937188 fixes to returning a pool for connection string (and alte…
sfc-gh-mhofman May 8, 2024
04633e2
SNOW-938188 validation of session properties for protecting unauthori…
sfc-gh-mhofman May 9, 2024
caf1eed
SNOW-937188 fixes for KeyPairAuth params validation
sfc-gh-mhofman May 9, 2024
1963f28
SNOW-937188 fixes to Authenticator validation (moved validation from …
sfc-gh-mhofman May 9, 2024
191bacc
SNOW-937188 connection string validation fixes
sfc-gh-mhofman May 9, 2024
b8e3634
SNOW-937188 fixes to testing failures after moving validation to sess…
sfc-gh-mhofman May 9, 2024
bcce8ef
SNOW-937188 added test to cover pool retrieval not working for invali…
sfc-gh-mhofman May 9, 2024
6613f10
SNOW-1406763 Test for password with special characters
sfc-gh-knozderko May 13, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ name: DotNet Build and Test
# Triggers the workflow on push or pull request events but only for the master branch
on:
push:
branches: [ master ]
branches: [ master, pool/SNOW-860872-connection-pool ]
pull_request:
branches: [ master ]
branches: [ master, pool/SNOW-860872-connection-pool ]
workflow_dispatch:
inputs:
logLevel:
Expand Down Expand Up @@ -61,7 +61,7 @@ jobs:
run: |
cd Snowflake.Data.Tests
dotnet restore
dotnet build -f ${{ matrix.dotnet }}
dotnet build -f ${{ matrix.dotnet }} '-p:DefineAdditionalConstants=SF_PUBLIC_ENVIRONMENT'
- name: Run Tests
run: |
cd Snowflake.Data.Tests
Expand Down Expand Up @@ -118,7 +118,7 @@ jobs:
- name: Build Driver
run: |
dotnet restore
dotnet build
dotnet build '-p:DefineAdditionalConstants=SF_PUBLIC_ENVIRONMENT'
- name: Run Tests
run: |
cd Snowflake.Data.Tests
Expand Down Expand Up @@ -175,7 +175,7 @@ jobs:
- name: Build Driver
run: |
dotnet restore
dotnet build
dotnet build '-p:DefineAdditionalConstants=SF_PUBLIC_ENVIRONMENT'
- name: Run Tests
run: |
cd Snowflake.Data.Tests
Expand Down
12 changes: 12 additions & 0 deletions CodingConventions.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,18 @@ public class ExampleClass
}
```

#### Property

Use PascalCase, eg. `SomeProperty`.

```csharp
public ExampleProperty
{
get;
set;
}
```

### Local variables

Use camelCase, eg. `someVariable`.
Expand Down
19 changes: 15 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,12 @@ The following table lists all valid connection properties:
| CLIENT_CONFIG_FILE | No | The location of the client configuration json file. In this file you can configure easy logging feature. |
| ALLOWUNDERSCORESINHOST | No | Specifies whether to allow underscores in account names. This impacts PrivateLink customers whose account names contain underscores. In this situation, you must override the default value by setting allowUnderscoresInHost to true. |
| QUERY_TAG | No | Optional string that can be used to tag queries and other SQL statements executed within a connection. The tags are displayed in the output of the QUERY_HISTORY , QUERY_HISTORY_BY_* functions. |
| MAXPOOLSIZE | No | Maximum number of connections in a pool. Default value is 10. `maxPoolSize` value cannot be lower than `minPoolSize` value. |
| MINPOOLSIZE | No | Expected minimum number of connections in pool. When you get a connection from the pool, more connections might be initialised in background to increase the pool size to `minPoolSize`. If you specify 0 or 1 there will be no attempts to create extra initialisations in background. The default value is 2. `maxPoolSize` value cannot be lower than `minPoolSize` value. The parameter is used only in a new version of connection pool. |
| CHANGEDSESSION | No | Specifies what should happen with a closed connection when some of its session variables are altered (e. g. you used `ALTER SESSION SET SCHEMA` to change the databese schema). The default behaviour is `OriginalPool` which means the session stays in the original pool. Currently no other option is possible. Parameter used only in a new version of connection pool. |
| WAITINGFORIDLESESSIONTIMEOUT | No | Timeout for waiting for an idle session when pool is full. It happens when there is no idle session and we cannot create a new one because of reaching `maxPoolSize`. The default value is 30 seconds. Usage of units possible and allowed are: e. g. `1000ms` (milliseconds), `15s` (seconds), `2m` (minutes) where seconds are default for a skipped postfix. Special values: `0` - immediate fail for new connection to open when session is full. You cannot specify infinite value. |
| EXPIRATIONTIMEOUT | No | Timeout for using each connection. Connections which last more than specified timeout are considered to be expired and are being removed from the pool. The default is 1 hour. Usage of units possible and allowed are: e. g. `360000ms` (milliseconds), `3600s` (seconds), `60m` (minutes) where seconds are default for a skipped postfix. Special values: `0` - immediate expiration of the connection just after its creation. Expiration timeout cannot be set to infinity. |
| POOLINGENABLED | No | Boolean flag indicating if the connection should be a part of a pool. The default value is `true`. |

<br />

Expand Down Expand Up @@ -822,6 +828,11 @@ CancellationTokenSource cancellationTokenSource = new CancellationTokenSource()
((SnowflakeDbConnection)conn).CloseAsync(cancellationTokenSource.Token);
```

## Evict the Connection

For the open connection, call the `PreventPooling()` to mark the connection to be removed on close instead being still pooled.
The busy sessions counter will be decreased when the connection is closed.

## Logging

The Snowflake Connector for .NET uses [log4net](http://logging.apache.org/log4net/) as the logging framework.
Expand Down Expand Up @@ -980,7 +991,7 @@ dotnet-coverage collect "dotnet test --framework net472 --no-build -l console;ve

## Notice

1. CVE-2019-0820 -
1. CVE-2019-0820 -
This CVE has been reported in systems.text.regularexpressions.dll which is used by the regular expressions packages - systems.text.regularexpressions.4.3.1.nupkg. This vulnerability manifests itself ONLY when the following .NET runtime environments are being used:

* v1.0 branch: 1.0 - 1.0.16 (exclusive)
Expand All @@ -990,7 +1001,7 @@ dotnet-coverage collect "dotnet test --framework net472 --no-build -l console;ve

In order to mitigate this vulnerability, we recommend to update to higher Runtime versions. If you're already running on a .NET Runtime version higher than the ones listed above, you're not going to be affected by this vulnerability.

2. Logging -
2. Logging -
Snowflake has identified an issue on Feb 20, 2020, with our logging code for the .NET drivers in which we write Master and Session tokens in the clear to the debug logs. The debug logs are collected locally on the drive where your programs are running. This issue impacts only those instances where the programs are run with debug flags enabled, i.e. setting the log level value= "Debug” or “All" in the log4Net config

Under normal conditions, the Master and Session tokens captured in the log files are short-lived for about 4 and 1 hours, respectively. They will expire after the 4-hour window unless explicitly refreshed, in which case they could be refreshed indefinitely.
Expand All @@ -1003,8 +1014,8 @@ dotnet-coverage collect "dotnet test --framework net472 --no-build -l console;ve
- If you cannot upgrade for any reason, please ensure all debugging is disabled
- If you are concerned about a potential compromise, contact Snowflake Customer Support for assistance with invalidating all active sessions/tokens.

3. Global HTTP connection settings -
Snowflake has identified an issue where the driver is globally enforcing TLS 1.2 and certificate revocation checks with the .NET Driver v1.2.1 and earlier versions.
3. Global HTTP connection settings -
Snowflake has identified an issue where the driver is globally enforcing TLS 1.2 and certificate revocation checks with the .NET Driver v1.2.1 and earlier versions.
Starting with v2.0.0, the driver will set these locally.

Note that the driver is now targeting .NET 6.0. When upgrading, you might also need to run “Update-Package -reinstall” to update the dependencies.
Original file line number Diff line number Diff line change
@@ -0,0 +1,197 @@
using System.Data.Common;
using System.Threading;
using System.Threading.Tasks;
using Moq;
using NUnit.Framework;
using Snowflake.Data.Client;
using Snowflake.Data.Core;
using Snowflake.Data.Core.Session;
using Snowflake.Data.Log;
using Snowflake.Data.Tests.Mock;
using Snowflake.Data.Tests.Util;

namespace Snowflake.Data.Tests.IntegrationTests
{
[TestFixture]
[NonParallelizable]
public class ConnectionMultiplePoolsAsyncIT: SFBaseTestAsync
{
private readonly PoolConfig _previousPoolConfig = new PoolConfig();
private readonly SFLogger logger = SFLoggerFactory.GetLogger<SFConnectionIT>();

[SetUp]
public new void BeforeTest()
{
SnowflakeDbConnectionPool.SetConnectionPoolVersion(ConnectionPoolType.MultipleConnectionPool);
SnowflakeDbConnectionPool.ClearAllPools();
}

[TearDown]
public new void AfterTest()
{
_previousPoolConfig.Reset();
}

[Test]
public async Task TestAddToPoolOnOpenAsync()
{
// arrange
var connection = new SnowflakeDbConnection(ConnectionString + "minPoolSize=1");

// act
await connection.OpenAsync().ConfigureAwait(false);

// assert
var pool = SnowflakeDbConnectionPool.GetPool(connection.ConnectionString);
Assert.AreEqual(1, pool.GetCurrentPoolSize());

// cleanup
await connection.CloseAsync(CancellationToken.None).ConfigureAwait(false);
}

[Test]
public async Task TestFailForInvalidConnectionAsync()
{
// arrange
var invalidConnectionString = ";connection_timeout=123";
var connection = new SnowflakeDbConnection(invalidConnectionString);

// act
try
{
await connection.OpenAsync().ConfigureAwait(false);
Assert.Fail("OpenAsync should fail for invalid connection string");
}
catch {}
var thrown = Assert.Throws<SnowflakeDbException>(() => SnowflakeDbConnectionPool.GetPool(connection.ConnectionString));

// assert
Assert.That(thrown.Message, Does.Contain("Required property ACCOUNT is not provided"));
}

[Test]
public void TestConnectionPoolWithInvalidOpenAsync()
{
// make the connection string unique so it won't pick up connection
// pooled by other test cases.
string connStr = ConnectionString + "minPoolSize=0;maxPoolSize=10;application=conn_pool_test_invalid_openasync2";
using (var connection = new SnowflakeDbConnection())
{
connection.ConnectionString = connStr;
// call openAsync but do not wait and destroy it direct
// so the session is initialized with empty token
connection.OpenAsync();
}

// use the same connection string to make a new connection
// to ensure the invalid connection made previously is not pooled
using (var connection1 = new SnowflakeDbConnection())
{
connection1.ConnectionString = connStr;
// this will not open a new session but get the invalid connection from pool
connection1.Open();
// Now run query with connection1
var command = connection1.CreateCommand();
command.CommandText = "select 1, 2, 3";

try
{
using (var reader = command.ExecuteReader())
{
while (reader.Read())
{
for (int i = 0; i < reader.FieldCount; i++)
{
// Process each column as appropriate
reader.GetFieldValue<object>(i);
}
}
}
}
catch (SnowflakeDbException)
{
// fail the test case if anything wrong.
Assert.Fail();
}
}
}

[Test]
public async Task TestMinPoolSizeAsync()
{
// arrange
var connection = new SnowflakeDbConnection();
connection.ConnectionString = ConnectionString + "application=TestMinPoolSizeAsync;minPoolSize=3";

// act
await connection.OpenAsync().ConfigureAwait(false);
Thread.Sleep(3000);

// assert
var pool = SnowflakeDbConnectionPool.GetPool(connection.ConnectionString);
Assert.AreEqual(3, pool.GetCurrentPoolSize());

// cleanup
await connection.CloseAsync(CancellationToken.None).ConfigureAwait(false);
}

[Test]
public async Task TestPreventConnectionFromReturningToPool()
{
// arrange
var connectionString = ConnectionString + "minPoolSize=0";
var connection = new SnowflakeDbConnection(connectionString);
await connection.OpenAsync().ConfigureAwait(false);
var pool = SnowflakeDbConnectionPool.GetPool(connectionString);
Assert.AreEqual(1, pool.GetCurrentPoolSize());

// act
connection.PreventPooling();
await connection.CloseAsync(CancellationToken.None).ConfigureAwait(false);

// assert
Assert.AreEqual(0, pool.GetCurrentPoolSize());
}

[Test]
public async Task TestReleaseConnectionWhenRollbackFailsAsync()
{
// arrange
var connectionString = ConnectionString + "minPoolSize=0";
var pool = SnowflakeDbConnectionPool.GetPool(connectionString);
var commandThrowingExceptionOnlyForRollback = MockHelper.CommandThrowingExceptionOnlyForRollback();
var mockDbProviderFactory = new Mock<DbProviderFactory>();
mockDbProviderFactory.Setup(p => p.CreateCommand()).Returns(commandThrowingExceptionOnlyForRollback.Object);
Assert.AreEqual(0, pool.GetCurrentPoolSize());
var connection = new TestSnowflakeDbConnection(mockDbProviderFactory.Object);
connection.ConnectionString = connectionString;
await connection.OpenAsync().ConfigureAwait(false);
connection.BeginTransaction(); // not using async version because it is not available on .net framework
Assert.AreEqual(true, connection.HasActiveExplicitTransaction());

// act
await connection.CloseAsync(CancellationToken.None).ConfigureAwait(false);

// assert
Assert.AreEqual(0, pool.GetCurrentPoolSize(), "Should not return connection to the pool");
}

[Test(Description = "test connection pooling with concurrent connection using async calls")]
public void TestConcurrentConnectionPoolingAsync()
{
// add test case name in connection string to make in unique for each test case
// set short expiration timeout to cover the case that connection expired
string connStr = ConnectionString + ";application=TestConcurrentConnectionPoolingAsync2;ExpirationTimeout=3";
ConnectionSinglePoolCacheAsyncIT.ConcurrentPoolingAsyncHelper(connStr, true, 7, 100, 2);
}

[Test(Description = "test connection pooling with concurrent connection and using async calls no close call for connection. Connection is closed when Dispose() is called by framework.")]
public void TestConcurrentConnectionPoolingDisposeAsync()
{
// add test case name in connection string to make in unique for each test case
// set short expiration timeout to cover the case that connection expired
string connStr = ConnectionString + ";application=TestConcurrentConnectionPoolingDisposeAsync2;ExpirationTimeout=3";
ConnectionSinglePoolCacheAsyncIT.ConcurrentPoolingAsyncHelper(connStr, false, 7, 100, 2);
}
}
}
Loading
Loading