Skip to content

Commit d9efa74

Browse files
author
Johnny Pham
authored
Test | Add lock when using ClearSqlConnectionGlobalProvidersk (#1461)
1 parent 330de76 commit d9efa74

File tree

4 files changed

+101
-99
lines changed

4 files changed

+101
-99
lines changed

src/Microsoft.Data.SqlClient/tests/FunctionalTests/AlwaysEncryptedTests/ExceptionRegisterKeyStoreProvider.cs

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -85,21 +85,24 @@ public void TestEmptyProviderName()
8585
[Fact]
8686
public void TestCanSetGlobalProvidersOnlyOnce()
8787
{
88-
Utility.ClearSqlConnectionGlobalProviders();
88+
lock (Utility.ClearSqlConnectionGlobalProvidersLock)
89+
{
90+
Utility.ClearSqlConnectionGlobalProviders();
8991

90-
IDictionary<string, SqlColumnEncryptionKeyStoreProvider> customProviders =
91-
new Dictionary<string, SqlColumnEncryptionKeyStoreProvider>()
92-
{
92+
IDictionary<string, SqlColumnEncryptionKeyStoreProvider> customProviders =
93+
new Dictionary<string, SqlColumnEncryptionKeyStoreProvider>()
94+
{
9395
{ DummyKeyStoreProvider.Name, new DummyKeyStoreProvider() }
94-
};
95-
SqlConnection.RegisterColumnEncryptionKeyStoreProviders(customProviders);
96+
};
97+
SqlConnection.RegisterColumnEncryptionKeyStoreProviders(customProviders);
9698

97-
InvalidOperationException e = Assert.Throws<InvalidOperationException>(
98-
() => SqlConnection.RegisterColumnEncryptionKeyStoreProviders(customProviders));
99-
string expectedMessage = SystemDataResourceManager.Instance.TCE_CanOnlyCallOnce;
100-
Assert.Contains(expectedMessage, e.Message);
99+
InvalidOperationException e = Assert.Throws<InvalidOperationException>(
100+
() => SqlConnection.RegisterColumnEncryptionKeyStoreProviders(customProviders));
101+
string expectedMessage = SystemDataResourceManager.Instance.TCE_CanOnlyCallOnce;
102+
Assert.Contains(expectedMessage, e.Message);
101103

102-
Utility.ClearSqlConnectionGlobalProviders();
104+
Utility.ClearSqlConnectionGlobalProviders();
105+
}
103106
}
104107

105108
[Fact]

src/Microsoft.Data.SqlClient/tests/FunctionalTests/AlwaysEncryptedTests/ExceptionsAlgorithmErrors.cs

Lines changed: 40 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ public void TestInvalidCipherText()
8282
[PlatformSpecific(TestPlatforms.Windows)]
8383
public void TestInvalidAlgorithmVersion()
8484
{
85-
string expectedMessage = string.Format(SystemDataResourceManager.Instance.TCE_InvalidAlgorithmVersion,
85+
string expectedMessage = string.Format(SystemDataResourceManager.Instance.TCE_InvalidAlgorithmVersion,
8686
40, "01");
8787
byte[] plainText = Encoding.Unicode.GetBytes("Hello World");
8888
byte[] cipherText = EncryptDataUsingAED(plainText, CertFixture.cek, CColumnEncryptionType.Deterministic);
@@ -112,7 +112,7 @@ public void TestInvalidAuthenticationTag()
112112
[PlatformSpecific(TestPlatforms.Windows)]
113113
public void TestNullColumnEncryptionAlgorithm()
114114
{
115-
string expectedMessage = string.Format(SystemDataResourceManager.Instance.TCE_NullColumnEncryptionAlgorithm,
115+
string expectedMessage = string.Format(SystemDataResourceManager.Instance.TCE_NullColumnEncryptionAlgorithm,
116116
"'AEAD_AES_256_CBC_HMAC_SHA256'");
117117
Object cipherMD = GetSqlCipherMetadata(0, 0, null, 1, 0x01);
118118
AddEncryptionKeyToCipherMD(cipherMD, CertFixture.encryptedCek, 0, 0, 0, new byte[] { 0x01, 0x02, 0x03 }, CertFixture.certificatePath, "MSSQL_CERTIFICATE_STORE", "RSA_OAEP");
@@ -148,32 +148,35 @@ public void TestUnknownEncryptionAlgorithmId()
148148
[PlatformSpecific(TestPlatforms.Windows)]
149149
public void TestUnknownCustomKeyStoreProvider()
150150
{
151-
// Clear out the existing providers (to ensure test reliability)
152-
ClearSqlConnectionGlobalProviders();
153-
154-
const string invalidProviderName = "Dummy_Provider";
155-
string expectedMessage = string.Format(SystemDataResourceManager.Instance.TCE_UnrecognizedKeyStoreProviderName,
156-
invalidProviderName, "'MSSQL_CERTIFICATE_STORE', 'MSSQL_CNG_STORE', 'MSSQL_CSP_PROVIDER'", "");
157-
Object cipherMD = GetSqlCipherMetadata(0, 1, null, 1, 0x03);
158-
AddEncryptionKeyToCipherMD(cipherMD, CertFixture.encryptedCek, 0, 0, 0, new byte[] { 0x01, 0x02, 0x03 }, CertFixture.certificatePath, invalidProviderName, "RSA_OAEP");
159-
byte[] plainText = Encoding.Unicode.GetBytes("HelloWorld");
160-
byte[] cipherText = EncryptDataUsingAED(plainText, CertFixture.cek, CColumnEncryptionType.Deterministic);
151+
lock (Utility.ClearSqlConnectionGlobalProvidersLock)
152+
{
153+
// Clear out the existing providers (to ensure test reliability)
154+
ClearSqlConnectionGlobalProviders();
161155

162-
Exception decryptEx = Assert.Throws<TargetInvocationException>(() => DecryptWithKey(plainText, cipherMD));
163-
Assert.Contains(expectedMessage, decryptEx.InnerException.Message);
156+
const string invalidProviderName = "Dummy_Provider";
157+
string expectedMessage = string.Format(SystemDataResourceManager.Instance.TCE_UnrecognizedKeyStoreProviderName,
158+
invalidProviderName, "'MSSQL_CERTIFICATE_STORE', 'MSSQL_CNG_STORE', 'MSSQL_CSP_PROVIDER'", "");
159+
Object cipherMD = GetSqlCipherMetadata(0, 1, null, 1, 0x03);
160+
AddEncryptionKeyToCipherMD(cipherMD, CertFixture.encryptedCek, 0, 0, 0, new byte[] { 0x01, 0x02, 0x03 }, CertFixture.certificatePath, invalidProviderName, "RSA_OAEP");
161+
byte[] plainText = Encoding.Unicode.GetBytes("HelloWorld");
162+
byte[] cipherText = EncryptDataUsingAED(plainText, CertFixture.cek, CColumnEncryptionType.Deterministic);
164163

165-
Exception encryptEx = Assert.Throws<TargetInvocationException>(() => EncryptWithKey(plainText, cipherMD));
166-
Assert.Contains(expectedMessage, encryptEx.InnerException.Message);
164+
Exception decryptEx = Assert.Throws<TargetInvocationException>(() => DecryptWithKey(plainText, cipherMD));
165+
Assert.Contains(expectedMessage, decryptEx.InnerException.Message);
166+
167+
Exception encryptEx = Assert.Throws<TargetInvocationException>(() => EncryptWithKey(plainText, cipherMD));
168+
Assert.Contains(expectedMessage, encryptEx.InnerException.Message);
167169

168-
ClearSqlConnectionGlobalProviders();
170+
ClearSqlConnectionGlobalProviders();
171+
}
169172
}
170173

171174
[Fact]
172175
[PlatformSpecific(TestPlatforms.Windows)]
173176
public void TestTceUnknownEncryptionAlgorithm()
174177
{
175178
const string unknownEncryptionAlgorithm = "Dummy";
176-
string expectedMessage = string.Format(SystemDataResourceManager.Instance.TCE_UnknownColumnEncryptionAlgorithm,
179+
string expectedMessage = string.Format(SystemDataResourceManager.Instance.TCE_UnknownColumnEncryptionAlgorithm,
177180
unknownEncryptionAlgorithm, "'AEAD_AES_256_CBC_HMAC_SHA256'");
178181
Object cipherMD = GetSqlCipherMetadata(0, 0, "Dummy", 1, 0x01);
179182
AddEncryptionKeyToCipherMD(cipherMD, CertFixture.encryptedCek, 0, 0, 0, new byte[] { 0x01, 0x02, 0x03 }, CertFixture.certificatePath, "MSSQL_CERTIFICATE_STORE", "RSA_OAEP");
@@ -193,7 +196,7 @@ public void TestExceptionsFromCertStore()
193196
{
194197
byte[] corruptedCek = GenerateInvalidEncryptedCek(CertFixture.cek, ECEKCorruption.SIGNATURE);
195198

196-
string expectedMessage = string.Format(SystemDataResourceManager.Instance.TCE_KeyDecryptionFailedCertStore,
199+
string expectedMessage = string.Format(SystemDataResourceManager.Instance.TCE_KeyDecryptionFailedCertStore,
197200
"MSSQL_CERTIFICATE_STORE", BitConverter.ToString(corruptedCek, corruptedCek.Length - 10, 10));
198201

199202
Object cipherMD = GetSqlCipherMetadata(0, 1, null, 1, 0x01);
@@ -209,27 +212,30 @@ public void TestExceptionsFromCertStore()
209212
[PlatformSpecific(TestPlatforms.Windows)]
210213
public void TestExceptionsFromCustomKeyStore()
211214
{
212-
string expectedMessage = "Failed to decrypt a column encryption key";
215+
lock (Utility.ClearSqlConnectionGlobalProvidersLock)
216+
{
217+
string expectedMessage = "Failed to decrypt a column encryption key";
213218

214-
// Clear out the existing providers (to ensure test reliability)
215-
ClearSqlConnectionGlobalProviders();
219+
// Clear out the existing providers (to ensure test reliability)
220+
ClearSqlConnectionGlobalProviders();
216221

217-
IDictionary<string, SqlColumnEncryptionKeyStoreProvider> customProviders = new Dictionary<string, SqlColumnEncryptionKeyStoreProvider>();
218-
customProviders.Add(DummyKeyStoreProvider.Name, new DummyKeyStoreProvider());
219-
SqlConnection.RegisterColumnEncryptionKeyStoreProviders(customProviders);
222+
IDictionary<string, SqlColumnEncryptionKeyStoreProvider> customProviders = new Dictionary<string, SqlColumnEncryptionKeyStoreProvider>();
223+
customProviders.Add(DummyKeyStoreProvider.Name, new DummyKeyStoreProvider());
224+
SqlConnection.RegisterColumnEncryptionKeyStoreProviders(customProviders);
220225

221-
object cipherMD = GetSqlCipherMetadata(0, 1, null, 1, 0x01);
222-
AddEncryptionKeyToCipherMD(cipherMD, CertFixture.encryptedCek, 0, 0, 0, new byte[] { 0x01, 0x02, 0x03 }, CertFixture.certificatePath, "DummyProvider", "DummyAlgo");
223-
byte[] plainText = Encoding.Unicode.GetBytes("HelloWorld");
224-
byte[] cipherText = EncryptDataUsingAED(plainText, CertFixture.cek, CColumnEncryptionType.Deterministic);
226+
object cipherMD = GetSqlCipherMetadata(0, 1, null, 1, 0x01);
227+
AddEncryptionKeyToCipherMD(cipherMD, CertFixture.encryptedCek, 0, 0, 0, new byte[] { 0x01, 0x02, 0x03 }, CertFixture.certificatePath, "DummyProvider", "DummyAlgo");
228+
byte[] plainText = Encoding.Unicode.GetBytes("HelloWorld");
229+
byte[] cipherText = EncryptDataUsingAED(plainText, CertFixture.cek, CColumnEncryptionType.Deterministic);
225230

226-
Exception decryptEx = Assert.Throws<TargetInvocationException>(() => DecryptWithKey(cipherText, cipherMD));
227-
Assert.Contains(expectedMessage, decryptEx.InnerException.Message);
231+
Exception decryptEx = Assert.Throws<TargetInvocationException>(() => DecryptWithKey(cipherText, cipherMD));
232+
Assert.Contains(expectedMessage, decryptEx.InnerException.Message);
228233

229-
Exception encryptEx = Assert.Throws<TargetInvocationException>(() => EncryptWithKey(cipherText, cipherMD));
230-
Assert.Contains(expectedMessage, encryptEx.InnerException.Message);
234+
Exception encryptEx = Assert.Throws<TargetInvocationException>(() => EncryptWithKey(cipherText, cipherMD));
235+
Assert.Contains(expectedMessage, encryptEx.InnerException.Message);
231236

232-
ClearSqlConnectionGlobalProviders();
237+
ClearSqlConnectionGlobalProviders();
238+
}
233239
}
234240
}
235241

src/Microsoft.Data.SqlClient/tests/FunctionalTests/AlwaysEncryptedTests/SqlColumnEncryptionCertificateStoreProviderShould.cs

Lines changed: 44 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -92,11 +92,6 @@ public class SqlColumnEncryptionCertificateStoreProviderWindowsShould : IClassFi
9292
/// </summary>
9393
private const int CipherTextStartIndex = IVStartIndex + IVLengthInBytes;
9494

95-
/// <summary>
96-
/// SetCustomColumnEncryptionKeyStoreProvider can be called only once in a process. To workaround that, we use this flag.
97-
/// </summary>
98-
private static bool s_testCustomEncryptioKeyStoreProviderExecutedOnce = false;
99-
10095
[Theory]
10196
[InvalidDecryptionParameters]
10297
[PlatformSpecific(TestPlatforms.Windows)]
@@ -326,55 +321,51 @@ public void TestAeadEncryptionReversal(string dataType, object data, Utility.CCo
326321
[PlatformSpecific(TestPlatforms.Windows)]
327322
public void TestCustomKeyProviderListSetter()
328323
{
329-
// SqlConnection.RegisterColumnEncryptionKeyStoreProviders can be called only once in a process.
330-
// This is a workaround to ensure re-runnability of the test.
331-
if (s_testCustomEncryptioKeyStoreProviderExecutedOnce)
324+
lock (Utility.ClearSqlConnectionGlobalProvidersLock)
332325
{
333-
return;
326+
string expectedMessage1 = "Column encryption key store provider dictionary cannot be null. Expecting a non-null value.";
327+
// Verify that we are able to set it to null.
328+
ArgumentException e1 = Assert.Throws<ArgumentNullException>(() => SqlConnection.RegisterColumnEncryptionKeyStoreProviders(null));
329+
Assert.Contains(expectedMessage1, e1.Message);
330+
331+
// A dictionary holding custom providers.
332+
IDictionary<string, SqlColumnEncryptionKeyStoreProvider> customProviders = new Dictionary<string, SqlColumnEncryptionKeyStoreProvider>();
333+
customProviders.Add(new KeyValuePair<string, SqlColumnEncryptionKeyStoreProvider>(@"DummyProvider", new DummyKeyStoreProvider()));
334+
335+
// Verify that setting a provider in the list with null value throws an exception.
336+
customProviders.Add(new KeyValuePair<string, SqlColumnEncryptionKeyStoreProvider>(@"CustomProvider", null));
337+
string expectedMessage2 = "Null reference specified for key store provider 'CustomProvider'. Expecting a non-null value.";
338+
ArgumentNullException e2 = Assert.Throws<ArgumentNullException>(() => SqlConnection.RegisterColumnEncryptionKeyStoreProviders(customProviders));
339+
Assert.Contains(expectedMessage2, e2.Message);
340+
customProviders.Remove(@"CustomProvider");
341+
342+
// Verify that setting a provider in the list with an empty provider name throws an exception.
343+
customProviders.Add(new KeyValuePair<string, SqlColumnEncryptionKeyStoreProvider>(@"", new DummyKeyStoreProvider()));
344+
string expectedMessage3 = "Invalid key store provider name specified. Key store provider names cannot be null or empty";
345+
ArgumentNullException e3 = Assert.Throws<ArgumentNullException>(() => SqlConnection.RegisterColumnEncryptionKeyStoreProviders(customProviders));
346+
Assert.Contains(expectedMessage3, e3.Message);
347+
348+
customProviders.Remove(@"");
349+
350+
// Verify that setting a provider in the list with name that starts with 'MSSQL_' throws an exception.
351+
customProviders.Add(new KeyValuePair<string, SqlColumnEncryptionKeyStoreProvider>(@"MSSQL_MyStore", new SqlColumnEncryptionCertificateStoreProvider()));
352+
string expectedMessage4 = "Invalid key store provider name 'MSSQL_MyStore'. 'MSSQL_' prefix is reserved for system key store providers.";
353+
ArgumentException e4 = Assert.Throws<ArgumentException>(() => SqlConnection.RegisterColumnEncryptionKeyStoreProviders(customProviders));
354+
Assert.Contains(expectedMessage4, e4.Message);
355+
356+
customProviders.Remove(@"MSSQL_MyStore");
357+
358+
// Verify that setting a provider in the list with name that starts with 'MSSQL_' but different case throws an exception.
359+
customProviders.Add(new KeyValuePair<string, SqlColumnEncryptionKeyStoreProvider>(@"MsSqL_MyStore", new SqlColumnEncryptionCertificateStoreProvider()));
360+
string expectedMessage5 = "Invalid key store provider name 'MsSqL_MyStore'. 'MSSQL_' prefix is reserved for system key store providers.";
361+
ArgumentException e5 = Assert.Throws<ArgumentException>(() => SqlConnection.RegisterColumnEncryptionKeyStoreProviders(customProviders));
362+
Assert.Contains(expectedMessage5, e5.Message);
363+
364+
customProviders.Remove(@"MsSqL_MyStore");
365+
366+
// Clear any providers set by other tests.
367+
Utility.ClearSqlConnectionGlobalProviders();
334368
}
335-
336-
string expectedMessage1 = "Column encryption key store provider dictionary cannot be null. Expecting a non-null value.";
337-
// Verify that we are able to set it to null.
338-
ArgumentException e1 = Assert.Throws<ArgumentNullException>(() => SqlConnection.RegisterColumnEncryptionKeyStoreProviders(null));
339-
Assert.Contains(expectedMessage1, e1.Message);
340-
341-
// A dictionary holding custom providers.
342-
IDictionary<string, SqlColumnEncryptionKeyStoreProvider> customProviders = new Dictionary<string, SqlColumnEncryptionKeyStoreProvider>();
343-
customProviders.Add(new KeyValuePair<string, SqlColumnEncryptionKeyStoreProvider>(@"DummyProvider", new DummyKeyStoreProvider()));
344-
345-
// Verify that setting a provider in the list with null value throws an exception.
346-
customProviders.Add(new KeyValuePair<string, SqlColumnEncryptionKeyStoreProvider>(@"CustomProvider", null));
347-
string expectedMessage2 = "Null reference specified for key store provider 'CustomProvider'. Expecting a non-null value.";
348-
ArgumentNullException e2 = Assert.Throws<ArgumentNullException>(() => SqlConnection.RegisterColumnEncryptionKeyStoreProviders(customProviders));
349-
Assert.Contains(expectedMessage2, e2.Message);
350-
customProviders.Remove(@"CustomProvider");
351-
352-
// Verify that setting a provider in the list with an empty provider name throws an exception.
353-
customProviders.Add(new KeyValuePair<string, SqlColumnEncryptionKeyStoreProvider>(@"", new DummyKeyStoreProvider()));
354-
string expectedMessage3 = "Invalid key store provider name specified. Key store provider names cannot be null or empty";
355-
ArgumentNullException e3 = Assert.Throws<ArgumentNullException>(() => SqlConnection.RegisterColumnEncryptionKeyStoreProviders(customProviders));
356-
Assert.Contains(expectedMessage3, e3.Message);
357-
358-
customProviders.Remove(@"");
359-
360-
// Verify that setting a provider in the list with name that starts with 'MSSQL_' throws an exception.
361-
customProviders.Add(new KeyValuePair<string, SqlColumnEncryptionKeyStoreProvider>(@"MSSQL_MyStore", new SqlColumnEncryptionCertificateStoreProvider()));
362-
string expectedMessage4 = "Invalid key store provider name 'MSSQL_MyStore'. 'MSSQL_' prefix is reserved for system key store providers.";
363-
ArgumentException e4 = Assert.Throws<ArgumentException>(() => SqlConnection.RegisterColumnEncryptionKeyStoreProviders(customProviders));
364-
Assert.Contains(expectedMessage4, e4.Message);
365-
366-
customProviders.Remove(@"MSSQL_MyStore");
367-
368-
// Verify that setting a provider in the list with name that starts with 'MSSQL_' but different case throws an exception.
369-
customProviders.Add(new KeyValuePair<string, SqlColumnEncryptionKeyStoreProvider>(@"MsSqL_MyStore", new SqlColumnEncryptionCertificateStoreProvider()));
370-
string expectedMessage5 = "Invalid key store provider name 'MsSqL_MyStore'. 'MSSQL_' prefix is reserved for system key store providers.";
371-
ArgumentException e5 = Assert.Throws<ArgumentException>(() => SqlConnection.RegisterColumnEncryptionKeyStoreProviders(customProviders));
372-
Assert.Contains(expectedMessage5, e5.Message);
373-
374-
customProviders.Remove(@"MsSqL_MyStore");
375-
376-
// Clear any providers set by other tests.
377-
Utility.ClearSqlConnectionGlobalProviders();
378369
}
379370

380371
[Theory]
@@ -502,7 +493,7 @@ public class CEKEncryptionReversalParameters : DataAttribute
502493
{
503494
public override IEnumerable<Object[]> GetData(MethodInfo testMethod)
504495
{
505-
yield return new object[2] { StoreLocation.CurrentUser , CurrentUserMyPathPrefix };
496+
yield return new object[2] { StoreLocation.CurrentUser, CurrentUserMyPathPrefix };
506497
// use localmachine cert path only when current user is Admin.
507498
if (CertificateFixture.IsAdmin)
508499
{

0 commit comments

Comments
 (0)