Skip to content

Commit

Permalink
Test | Fix akvtest issues (dotnet#1842)
Browse files Browse the repository at this point in the history
  • Loading branch information
Javad authored Nov 21, 2022
1 parent c765d83 commit 03f3053
Showing 1 changed file with 74 additions and 71 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -14,108 +14,111 @@ namespace Microsoft.Data.SqlClient.ManualTesting.Tests.AlwaysEncrypted
{
public class AKVTest : IClassFixture<SQLSetupStrategyAzureKeyVault>
{
private SQLSetupStrategyAzureKeyVault fixture;
private readonly string akvTableName;
private readonly SQLSetupStrategyAzureKeyVault _fixture;
private readonly string _akvTableName;

public AKVTest(SQLSetupStrategyAzureKeyVault fixture)
{
this.fixture = fixture;
akvTableName = fixture.AKVTestTable.Name;
_fixture = fixture;
_akvTableName = fixture.AKVTestTable.Name;

// Disable the cache to avoid false failures.
SqlConnection.ColumnEncryptionQueryMetadataCacheEnabled = false;
}

[ConditionalFact(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup), nameof(DataTestUtility.IsAKVSetupAvailable))]
[ConditionalFact(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringSetupForAE), nameof(DataTestUtility.IsAKVSetupAvailable))]
public void TestEncryptDecryptWithAKV()
{
using (SqlConnection sqlConnection = new SqlConnection(string.Concat(DataTestUtility.TCPConnectionString, @";Column Encryption Setting = Enabled;")))
SqlConnectionStringBuilder builder = new(DataTestUtility.TCPConnectionStringHGSVBS)
{
sqlConnection.Open();

Customer customer = new Customer(45, "Microsoft", "Corporation");

// Start a transaction and either commit or rollback based on the test variation.
using (SqlTransaction sqlTransaction = sqlConnection.BeginTransaction())
{
DatabaseHelper.InsertCustomerData(sqlConnection, sqlTransaction, akvTableName, customer);
sqlTransaction.Commit();
}

// Test INPUT parameter on an encrypted parameter
using SqlCommand sqlCommand = new SqlCommand($"SELECT CustomerId, FirstName, LastName FROM [{akvTableName}] WHERE FirstName = @firstName",
sqlConnection);
SqlParameter customerFirstParam = sqlCommand.Parameters.AddWithValue(@"firstName", @"Microsoft");
customerFirstParam.Direction = System.Data.ParameterDirection.Input;
customerFirstParam.ForceColumnEncryption = true;

using SqlDataReader sqlDataReader = sqlCommand.ExecuteReader();
DatabaseHelper.ValidateResultSet(sqlDataReader);
ColumnEncryptionSetting = SqlConnectionColumnEncryptionSetting.Enabled,
AttestationProtocol = SqlConnectionAttestationProtocol.NotSpecified,
EnclaveAttestationUrl = ""
};
using SqlConnection sqlConnection = new (builder.ConnectionString);

sqlConnection.Open();
Customer customer = new(45, "Microsoft", "Corporation");

// Start a transaction and either commit or rollback based on the test variation.
using (SqlTransaction sqlTransaction = sqlConnection.BeginTransaction())
{
DatabaseHelper.InsertCustomerData(sqlConnection, sqlTransaction, _akvTableName, customer);
sqlTransaction.Commit();
}

// Test INPUT parameter on an encrypted parameter
using SqlCommand sqlCommand = new ($"SELECT CustomerId, FirstName, LastName FROM [{_akvTableName}] WHERE FirstName = @firstName",
sqlConnection);
SqlParameter customerFirstParam = sqlCommand.Parameters.AddWithValue(@"firstName", @"Microsoft");
customerFirstParam.Direction = System.Data.ParameterDirection.Input;
customerFirstParam.ForceColumnEncryption = true;

using SqlDataReader sqlDataReader = sqlCommand.ExecuteReader();
DatabaseHelper.ValidateResultSet(sqlDataReader);
}

[ConditionalFact(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup), nameof(DataTestUtility.IsAKVSetupAvailable))]
[ConditionalFact(typeof(DataTestUtility), nameof(DataTestUtility.IsAKVSetupAvailable))]
[PlatformSpecific(TestPlatforms.Windows)]
public void TestRoundTripWithAKVAndCertStoreProvider()
{
using (SQLSetupStrategyCertStoreProvider certStoreFixture = new SQLSetupStrategyCertStoreProvider())
{
byte[] plainTextColumnEncryptionKey = ColumnEncryptionKey.GenerateRandomBytes(ColumnEncryptionKey.KeySizeInBytes);
byte[] encryptedColumnEncryptionKeyUsingAKV = fixture.AkvStoreProvider.EncryptColumnEncryptionKey(DataTestUtility.AKVUrl, @"RSA_OAEP", plainTextColumnEncryptionKey);
byte[] columnEncryptionKeyReturnedAKV2Cert = certStoreFixture.CertStoreProvider.DecryptColumnEncryptionKey(certStoreFixture.CspColumnMasterKey.KeyPath, @"RSA_OAEP", encryptedColumnEncryptionKeyUsingAKV);
Assert.True(plainTextColumnEncryptionKey.SequenceEqual(columnEncryptionKeyReturnedAKV2Cert), @"Roundtrip failed");

// Try the opposite.
byte[] encryptedColumnEncryptionKeyUsingCert = certStoreFixture.CertStoreProvider.EncryptColumnEncryptionKey(certStoreFixture.CspColumnMasterKey.KeyPath, @"RSA_OAEP", plainTextColumnEncryptionKey);
byte[] columnEncryptionKeyReturnedCert2AKV = fixture.AkvStoreProvider.DecryptColumnEncryptionKey(DataTestUtility.AKVUrl, @"RSA_OAEP", encryptedColumnEncryptionKeyUsingCert);
Assert.True(plainTextColumnEncryptionKey.SequenceEqual(columnEncryptionKeyReturnedCert2AKV), @"Roundtrip failed");
}
using SQLSetupStrategyCertStoreProvider certStoreFixture = new ();
byte[] plainTextColumnEncryptionKey = ColumnEncryptionKey.GenerateRandomBytes(ColumnEncryptionKey.KeySizeInBytes);
byte[] encryptedColumnEncryptionKeyUsingAKV = _fixture.AkvStoreProvider.EncryptColumnEncryptionKey(DataTestUtility.AKVUrl, @"RSA_OAEP", plainTextColumnEncryptionKey);
byte[] columnEncryptionKeyReturnedAKV2Cert = certStoreFixture.CertStoreProvider.DecryptColumnEncryptionKey(certStoreFixture.CspColumnMasterKey.KeyPath, @"RSA_OAEP", encryptedColumnEncryptionKeyUsingAKV);
Assert.True(plainTextColumnEncryptionKey.SequenceEqual(columnEncryptionKeyReturnedAKV2Cert), @"Roundtrip failed");

// Try the opposite.
byte[] encryptedColumnEncryptionKeyUsingCert = certStoreFixture.CertStoreProvider.EncryptColumnEncryptionKey(certStoreFixture.CspColumnMasterKey.KeyPath, @"RSA_OAEP", plainTextColumnEncryptionKey);
byte[] columnEncryptionKeyReturnedCert2AKV = _fixture.AkvStoreProvider.DecryptColumnEncryptionKey(DataTestUtility.AKVUrl, @"RSA_OAEP", encryptedColumnEncryptionKeyUsingCert);
Assert.True(plainTextColumnEncryptionKey.SequenceEqual(columnEncryptionKeyReturnedCert2AKV), @"Roundtrip failed");
}

[ConditionalFact(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup), nameof(DataTestUtility.IsAKVSetupAvailable))]
[ConditionalFact(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringSetupForAE), nameof(DataTestUtility.IsAKVSetupAvailable))]
public void TestLocalCekCacheIsScopedToProvider()
{
using (SqlConnection sqlConnection = new(string.Concat(DataTestUtility.TCPConnectionString, @";Column Encryption Setting = Enabled;")))
SqlConnectionStringBuilder builder = new(DataTestUtility.TCPConnectionStringHGSVBS)
{
sqlConnection.Open();
ColumnEncryptionSetting = SqlConnectionColumnEncryptionSetting.Enabled,
AttestationProtocol = SqlConnectionAttestationProtocol.NotSpecified,
EnclaveAttestationUrl = ""
};

using SqlConnection sqlConnection = new(builder.ConnectionString);

Customer customer = new(45, "Microsoft", "Corporation");
sqlConnection.Open();

// Test INPUT parameter on an encrypted parameter
using (SqlCommand sqlCommand = new($"SELECT CustomerId, FirstName, LastName FROM [{akvTableName}] WHERE FirstName = @firstName",
sqlConnection))
{
SqlParameter customerFirstParam = sqlCommand.Parameters.AddWithValue(@"firstName", @"Microsoft");
customerFirstParam.Direction = System.Data.ParameterDirection.Input;
customerFirstParam.ForceColumnEncryption = true;
// Test INPUT parameter on an encrypted parameter
using SqlCommand sqlCommand = new($"SELECT CustomerId, FirstName, LastName FROM [{_akvTableName}] WHERE FirstName = @firstName",
sqlConnection);
SqlParameter customerFirstParam = sqlCommand.Parameters.AddWithValue(@"firstName", @"Microsoft");
customerFirstParam.Direction = System.Data.ParameterDirection.Input;
customerFirstParam.ForceColumnEncryption = true;

SqlDataReader sqlDataReader = sqlCommand.ExecuteReader();
sqlDataReader.Close();
SqlDataReader sqlDataReader = sqlCommand.ExecuteReader();
sqlDataReader.Close();

SqlColumnEncryptionAzureKeyVaultProvider sqlColumnEncryptionAzureKeyVaultProvider =
new(new SqlClientCustomTokenCredential());
SqlColumnEncryptionAzureKeyVaultProvider sqlColumnEncryptionAzureKeyVaultProvider =
new(new SqlClientCustomTokenCredential());

Dictionary<string, SqlColumnEncryptionKeyStoreProvider> customProvider = new()
Dictionary<string, SqlColumnEncryptionKeyStoreProvider> customProvider = new()
{
{ SqlColumnEncryptionAzureKeyVaultProvider.ProviderName, sqlColumnEncryptionAzureKeyVaultProvider }
};

// execute a query using provider from command-level cache. this will cache the cek in the local cek cache
sqlCommand.RegisterColumnEncryptionKeyStoreProvidersOnCommand(customProvider);
SqlDataReader sqlDataReader2 = sqlCommand.ExecuteReader();
sqlDataReader2.Close();

// global cek cache and local cek cache are populated above
// when using a new per-command provider, it will only use its local cek cache
// the following query should fail due to an empty cek cache and invalid credentials
customProvider[SqlColumnEncryptionAzureKeyVaultProvider.ProviderName] =
new SqlColumnEncryptionAzureKeyVaultProvider(new ClientSecretCredential("tenant", "client", "secret"));
sqlCommand.RegisterColumnEncryptionKeyStoreProvidersOnCommand(customProvider);
Exception ex = Assert.Throws<SqlException>(() => sqlCommand.ExecuteReader());
Assert.Contains("ClientSecretCredential authentication failed", ex.Message);
}
}
// execute a query using provider from command-level cache. this will cache the cek in the local cek cache
sqlCommand.RegisterColumnEncryptionKeyStoreProvidersOnCommand(customProvider);
SqlDataReader sqlDataReader2 = sqlCommand.ExecuteReader();
sqlDataReader2.Close();

// global cek cache and local cek cache are populated above
// when using a new per-command provider, it will only use its local cek cache
// the following query should fail due to an empty cek cache and invalid credentials
customProvider[SqlColumnEncryptionAzureKeyVaultProvider.ProviderName] =
new SqlColumnEncryptionAzureKeyVaultProvider(new ClientSecretCredential("tenant", "client", "secret"));
sqlCommand.RegisterColumnEncryptionKeyStoreProvidersOnCommand(customProvider);
Exception ex = Assert.Throws<SqlException>(() => sqlCommand.ExecuteReader());
Assert.StartsWith("The current credential is not configured to acquire tokens for tenant", ex.InnerException.Message);
}

}
}

0 comments on commit 03f3053

Please sign in to comment.