Skip to content

Commit c91570e

Browse files
authored
Merge pull request #18091 from lilgreenbird/9.1.1
Documentation update for JDBC 9.2 release
2 parents 74a500b + 0113fc4 commit c91570e

12 files changed

Lines changed: 540 additions & 141 deletions

docs/connect/jdbc/always-encrypted-api-reference-for-the-jdbc-driver.md

Lines changed: 24 additions & 20 deletions
Large diffs are not rendered by default.

docs/connect/jdbc/azure-key-vault-sample-version-6.0.0.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
description: "Azure Key Vault sample version 6.0.0"
33
title: "Azure Key Vault sample version 6.0.0 | Microsoft Docs"
44
ms.custom: ""
5-
ms.date: "08/12/2019"
5+
ms.date: "01/29/2021"
66
ms.prod: sql
77
ms.prod_service: connectivity
88
ms.reviewer: ""
@@ -17,7 +17,7 @@ ms.author: v-daenge
1717

1818
## Sample application using Azure Key Vault feature
1919

20-
This application is runnable using JDBC Driver 6.0.0 and Azure-Keyvault (version 0.9.7), Adal4j (version 1.3.0), and their dependencies. The underlying dependencies can be resolved by adding these libraries to the pom file of the project as described [here](../../connect/jdbc/feature-dependencies-of-microsoft-jdbc-driver-for-sql-server.md):
20+
This application is runnable using JDBC Driver 6.0.0, Azure-Keyvault (version 0.9.7), Adal4j (version 1.3.0), and their dependencies. The underlying dependencies can be resolved by adding these libraries to the Project Object Model (POM) file of the project. For more information on feature dependencies, see [Feature dependencies of the Microsoft JDBC Driver for SQL Server](../../connect/jdbc/feature-dependencies-of-microsoft-jdbc-driver-for-sql-server.md).
2121

2222
```java
2323
import java.net.URISyntaxException;
@@ -222,5 +222,6 @@ public class AKV_600 {
222222

223223
## See also
224224

225+
[Azure Key vault sample version 9.2](../../connect/jdbc/azure-key-vault-sample-version-9.2.md)
225226
[Azure Key Vault sample version 7.0](../../connect/jdbc/azure-key-vault-sample-version-7.0.md)
226227
[Azure Key Vault sample version 6.2.2](../../connect/jdbc/azure-key-vault-sample-version-6.2.2.md)

docs/connect/jdbc/azure-key-vault-sample-version-6.2.2.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
description: "Azure Key Vault sample version 6.2.2"
33
title: "Azure Key Vault sample version 6.2.2 | Microsoft Docs"
44
ms.custom: ""
5-
ms.date: "08/12/2019"
5+
ms.date: "01/29/2021"
66
ms.prod: sql
77
ms.prod_service: connectivity
88
ms.reviewer: ""
@@ -17,7 +17,7 @@ ms.author: v-daenge
1717

1818
## Sample application using Azure Key Vault feature
1919

20-
This application is runnable using JDBC Driver 6.2.2 and 6.4.0 and Azure-Keyvault (version 1.0.0), Adal4j (version 1.4.0), and their dependencies. The underlying dependencies can be resolved by adding these libraries to the pom file of the project as described [here](../../connect/jdbc/feature-dependencies-of-microsoft-jdbc-driver-for-sql-server.md):
20+
This application is runnable using JDBC Driver 6.2.2 and 6.4.0, Azure-Keyvault (version 1.0.0), Adal4j (version 1.4.0), and their dependencies. The underlying dependencies can be resolved by adding these libraries to the pom file of the project as described [here](../../connect/jdbc/feature-dependencies-of-microsoft-jdbc-driver-for-sql-server.md):
2121

2222
```java
2323
import java.net.URISyntaxException;
@@ -184,5 +184,6 @@ public class AKV_6_2_2 {
184184

185185
## See also
186186

187+
[Azure Key vault sample version 9.2](../../connect/jdbc/azure-key-vault-sample-version-9.2.md)
187188
[Azure Key Vault sample version 7.0.0](../../connect/jdbc/azure-key-vault-sample-version-7.0.md)
188189
[Azure Key Vault sample version 6.0.0](../../connect/jdbc/azure-key-vault-sample-version-6.0.0.md)

docs/connect/jdbc/azure-key-vault-sample-version-7.0.md

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
---
2-
description: "Azure Key Vault sample"
3-
title: "Azure Key Vault sample | Microsoft Docs"
2+
description: "Azure Key Vault sample 7.0, 8.0"
3+
title: "Azure Key Vault sample 7.0, 8.0 | Microsoft Docs"
44
ms.custom: ""
5-
ms.date: "08/12/2019"
5+
ms.date: "01/29/2021"
66
ms.prod: sql
77
ms.prod_service: connectivity
88
ms.reviewer: ""
@@ -11,13 +11,13 @@ ms.topic: conceptual
1111
author: David-Engel
1212
ms.author: v-daenge
1313
---
14-
# Azure Key Vault sample
14+
# Azure Key Vault sample 7.0, 8.0
1515

1616
[!INCLUDE[Driver_JDBC_Download](../../includes/driver_jdbc_download.md)]
1717

1818
## Sample application using Azure Key Vault feature
1919

20-
This application is runnable using JDBC Driver 7.0 and above and Azure-Keyvault (version 1.0.0), Adal4j (version 1.6.0), and their dependencies. The underlying dependencies can be resolved by adding these libraries to the pom file of the project as described [here](../../connect/jdbc/feature-dependencies-of-microsoft-jdbc-driver-for-sql-server.md):
20+
This application is runnable using JDBC Driver 7.0, 8.0, Azure-Keyvault (version 1.0.0), Adal4j (version 1.6.0), and their dependencies. The underlying dependencies can be resolved by adding these libraries to the Project Object Model (POM) file of the project. For more information on feature dependencies, see [Feature dependencies of the Microsoft JDBC Driver for SQL Server](../../connect/jdbc/feature-dependencies-of-microsoft-jdbc-driver-for-sql-server.md).
2121

2222
```java
2323
import java.net.URISyntaxException;
@@ -240,5 +240,6 @@ public class AKV {
240240

241241
## See also
242242

243+
[Azure Key vault sample version 9.2](../../connect/jdbc/azure-key-vault-sample-version-9.2.md)
243244
[Azure Key vault sample version 6.2.2](../../connect/jdbc/azure-key-vault-sample-version-6.2.2.md)
244245
[Azure Key vault sample version 6.0.0](../../connect/jdbc/azure-key-vault-sample-version-6.0.0.md)
Lines changed: 248 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,248 @@
1+
---
2+
description: "This JDBC code example demonstrates how to use Azure Key Vault as your key store provider when using Always Encrypted."
3+
title: "Azure Key Vault sample"
4+
ms.custom: ""
5+
ms.date: "01/29/2021"
6+
7+
ms.prod: sql
8+
ms.prod_service: connectivity
9+
ms.reviewer: ""
10+
ms.technology: connectivity
11+
ms.topic: conceptual
12+
author: lilgreenbird
13+
ms.author: v-susanh
14+
---
15+
# Azure Key Vault sample
16+
17+
[!INCLUDE[Driver_JDBC_Download](../../includes/driver_jdbc_download.md)]
18+
19+
## Sample application using Azure Key Vault feature
20+
21+
This application is runnable using JDBC Driver 9.2 and above, Azure-Security-Keyvault (version 4.2.1), Azure-Identity (version 1.1.3), and their dependencies. The underlying dependencies can be resolved by adding these libraries to the Project Object Model (POM) file of the project. For more information on feature dependencies, see [Feature dependencies of the Microsoft JDBC Driver for SQL Server](../../connect/jdbc/feature-dependencies-of-microsoft-jdbc-driver-for-sql-server.md).
22+
23+
```java
24+
import java.net.URISyntaxException;
25+
import java.sql.Connection;
26+
import java.sql.DriverManager;
27+
import java.sql.PreparedStatement;
28+
import java.sql.ResultSet;
29+
import java.sql.SQLException;
30+
import java.sql.Statement;
31+
import java.util.HashMap;
32+
import java.util.Map;
33+
import java.util.concurrent.ExecutorService;
34+
import java.util.concurrent.Executors;
35+
import java.util.concurrent.Future;
36+
37+
import com.microsoft.aad.msal4j.IAuthenticationResult;
38+
import com.microsoft.aad.msal4j.PublicClientApplication;
39+
import com.microsoft.aad.msal4j.UserNamePasswordParameters;
40+
41+
import com.microsoft.sqlserver.jdbc.SQLServerColumnEncryptionAzureKeyVaultProvider;
42+
import com.microsoft.sqlserver.jdbc.SQLServerColumnEncryptionKeyStoreProvider;
43+
import com.microsoft.sqlserver.jdbc.SQLServerConnection;
44+
import com.microsoft.sqlserver.jdbc.SQLServerException;
45+
import com.microsoft.sqlserver.jdbc.SQLServerKeyVaultAuthenticationCallback;
46+
47+
public class AKV {
48+
49+
static String connectionUrl = "jdbc:sqlserver://localhost;integratedSecurity=true;database=test;columnEncryptionSetting=enabled";
50+
static String applicationClientID = "Your Client ID";
51+
static String applicationKey = "Your Application Key";
52+
static String keyID = "Your Key ID";
53+
static String cmkName = "AKV_CMK_JDBC";
54+
static String cekName = "AKV_CEK_JDBC";
55+
static String akvTable = "akvTable";
56+
57+
static String createTableSQL = "create table " + akvTable + " ("
58+
+ "PlainNvarcharMax nvarchar(max) null,"
59+
+ "RandomizedNvarcharMax nvarchar(max) COLLATE Latin1_General_BIN2 ENCRYPTED WITH (ENCRYPTION_TYPE = RANDOMIZED, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = "
60+
+ cekName + ") NULL,"
61+
+ "DeterministicNvarcharMax nvarchar(max) COLLATE Latin1_General_BIN2 ENCRYPTED WITH (ENCRYPTION_TYPE = DETERMINISTIC, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = "
62+
+ cekName + ") NULL" + ");";
63+
64+
public static void main(String[] args)
65+
throws ClassNotFoundException, Exception {
66+
Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
67+
try (Connection connection = DriverManager.getConnection(connectionUrl);
68+
Statement statement = connection.createStatement()) {
69+
statement.execute("DBCC FREEPROCCACHE");
70+
71+
statement.execute("DBCC FREEPROCCACHE");
72+
System.out.println("Create SQLServerColumnEncryptionAzureKeyVaultProvider with 'authenticationCallback'");
73+
/* Constructor added in 7.0.0 driver version [Supports SQLServerKeyVaultAuthenticationCallback in 7.0 for backwards compatibility]
74+
* This constructor is recommended to replace the above deprecated constructor */
75+
SQLServerColumnEncryptionAzureKeyVaultProvider akvProvider2 = new SQLServerColumnEncryptionAzureKeyVaultProvider(
76+
tryAuthenticationCallback());
77+
setupKeyStoreProviders(akvProvider2.getName(), akvProvider2);
78+
testAKV(akvProvider2.getName(), akvProvider2, connection, statement);
79+
80+
statement.execute("DBCC FREEPROCCACHE");
81+
System.out.println("Create SQLServerColumnEncryptionAzureKeyVaultProvider with 'clientId' and 'clientKey'");
82+
/* Constructor added in 6.2.2 driver version [Continued Support] */
83+
SQLServerColumnEncryptionAzureKeyVaultProvider akvProvider3 = new SQLServerColumnEncryptionAzureKeyVaultProvider(
84+
applicationClientID, applicationKey);
85+
setupKeyStoreProviders(akvProvider3.getName(), akvProvider3);
86+
testAKV(akvProvider3.getName(), akvProvider3, connection, statement);
87+
88+
statement.execute("DBCC FREEPROCCACHE");
89+
System.out.println("Create SQLServerColumnEncryptionAzureKeyVaultProvider with 'token credential'");
90+
/* see Azure Identity client library for Java
91+
* https://docs.microsoft.com/java/api/overview/azure/identity-readme?view=azure-java-stable */
92+
ClientSecretCredential tokenCredential = new ClientSecretCredentialBuilder().tenantId(tenantID)
93+
.clientId(applicationClientID).clientSecret(applicationKey).build();
94+
/* Constructor added in 9.2.0 driver version */
95+
SQLServerColumnEncryptionAzureKeyVaultProvider akvProvider4 = new SQLServerColumnEncryptionAzureKeyVaultProvider(
96+
tokenCredential);
97+
setupKeyStoreProviders(akvProvider4.getName(), akvProvider4);
98+
testAKV(akvProvider4.getName(), akvProvider4, connection, statement);
99+
100+
System.exit(0);
101+
}
102+
}
103+
104+
private static SQLServerKeyVaultAuthenticationCallback tryAuthenticationCallback()
105+
throws URISyntaxException, SQLServerException {
106+
SQLServerKeyVaultAuthenticationCallback authenticationCallback = new SQLServerKeyVaultAuthenticationCallback() {
107+
108+
@Override
109+
public String getAccessToken(String authority, String resource, String scope) {
110+
try { IClientCredential credential = ClientCredentialFactory.createFromSecret(applicationKey);
111+
ConfidentialClientApplication confidentialClientApplication = ConfidentialClientApplication
112+
.builder(applicationClientID, credential).authority(authority).build();
113+
Set<String> scopes = new HashSet<>();
114+
scopes.add(scope);
115+
return confidentialClientApplication.acquireToken(ClientCredentialParameters.builder(scopes).build()).get().accessToken();
116+
} catch (Exception e) {
117+
fail(TestResource.getResource("R_unexpectedException") + e.getMessage());
118+
}
119+
return null;
120+
}
121+
};
122+
123+
return authenticationCallback;
124+
125+
}
126+
127+
private static void testAKV(String CUSTOM_AKV_PROVIDER_NAME,
128+
SQLServerColumnEncryptionKeyStoreProvider akvProvider,
129+
Connection connection, Statement statement)
130+
throws SQLException, InterruptedException {
131+
132+
dropTable(statement);
133+
dropKeys(statement);
134+
135+
System.out.println("createCMK");
136+
createCMK(CUSTOM_AKV_PROVIDER_NAME, statement);
137+
138+
System.out.println("createCEK");
139+
createCEK(akvProvider, statement);
140+
141+
System.out.println("create Table");
142+
statement.execute(createTableSQL);
143+
144+
System.out.println("populate");
145+
populateCharNormalCase(connection);
146+
147+
System.out.println("run the test");
148+
testChar(statement);
149+
}
150+
151+
private static void setupKeyStoreProviders(String CUSTOM_AKV_PROVIDER_NAME,
152+
SQLServerColumnEncryptionKeyStoreProvider akvProvider)
153+
throws SQLServerException {
154+
/* unregister all previously registered providers if any */
155+
SQLServerConnection.unregisterColumnEncryptionKeyStoreProviders();
156+
Map<String, SQLServerColumnEncryptionKeyStoreProvider> map1 = new HashMap<String, SQLServerColumnEncryptionKeyStoreProvider>();
157+
map1.put(CUSTOM_AKV_PROVIDER_NAME, akvProvider);
158+
SQLServerConnection.registerColumnEncryptionKeyStoreProviders(map1);
159+
}
160+
161+
private static void dropTable(Statement statement) throws SQLException {
162+
statement.executeUpdate("if object_id('" + akvTable
163+
+ "','U') is not null" + " drop table " + akvTable);
164+
}
165+
166+
private static void dropKeys(Statement statement) throws SQLException {
167+
statement.executeUpdate(
168+
"if exists (SELECT name from sys.column_encryption_keys where name='"
169+
+ cekName + "')" + " begin"
170+
+ " drop column encryption key " + cekName + " end");
171+
statement.executeUpdate(
172+
"if exists (SELECT name from sys.column_master_keys where name='"
173+
+ cmkName + "')" + " begin" + " drop column master key "
174+
+ cmkName + " end");
175+
}
176+
177+
private static void createCMK(String CUSTOM_AKV_PROVIDER_NAME,
178+
Statement statement) throws SQLException {
179+
String _createColumnMasterKeyTemplate = String.format(
180+
"CREATE COLUMN MASTER KEY [%s] WITH ( KEY_STORE_PROVIDER_NAME = '%s', KEY_PATH = '%s');",
181+
cmkName, CUSTOM_AKV_PROVIDER_NAME, keyID);
182+
statement.execute(_createColumnMasterKeyTemplate);
183+
}
184+
185+
private static void createCEK(
186+
SQLServerColumnEncryptionKeyStoreProvider storeProvider,
187+
Statement statement) throws SQLServerException, SQLException {
188+
String letters = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
189+
byte[] valuesDefault = letters.getBytes();
190+
byte[] key = storeProvider.encryptColumnEncryptionKey(keyID, "RSA_OAEP",
191+
valuesDefault);
192+
String cekSql = "CREATE COLUMN ENCRYPTION KEY " + cekName
193+
+ " WITH VALUES " + "(COLUMN_MASTER_KEY = " + cmkName
194+
+ ", ALGORITHM = 'RSA_OAEP', ENCRYPTED_VALUE = 0x"
195+
+ bytesToHexString(key, key.length) + ")" + ";";
196+
statement.execute(cekSql);
197+
}
198+
199+
final static char[] hexChars = {'0', '1', '2', '3', '4', '5', '6', '7', '8',
200+
'9', 'A', 'B', 'C', 'D', 'E', 'F'};
201+
202+
private static String bytesToHexString(byte[] b, int length) {
203+
StringBuilder sb = new StringBuilder(length * 2);
204+
for (int i = 0; i < length; i++) {
205+
int hexVal = b[i] & 0xFF;
206+
sb.append(hexChars[(hexVal & 0xF0) >> 4]);
207+
sb.append(hexChars[(hexVal & 0x0F)]);
208+
}
209+
return sb.toString();
210+
}
211+
212+
private static void populateCharNormalCase(Connection connection)
213+
throws SQLException {
214+
String sql = "insert into " + akvTable + " values(?,?,?)";
215+
try (PreparedStatement pstmt = connection.prepareStatement(sql)) {
216+
for (int i = 1; i <= 5; i++) { //Insert 5 rows
217+
for (int j = 1; j <= 3; j++) {
218+
pstmt.setNString(j, "Row " + i + " Column " + j);
219+
}
220+
pstmt.execute();
221+
}
222+
}
223+
}
224+
225+
/**
226+
* Rerieves the table
227+
*
228+
* @throws SQLException
229+
*/
230+
private static void testChar(Statement statement) throws SQLException {
231+
try (ResultSet rs = statement
232+
.executeQuery("select * from " + akvTable);) {
233+
int numberOfColumns = rs.getMetaData().getColumnCount();
234+
while (rs.next()) {
235+
for (int i = 1; i <= numberOfColumns; i++) {
236+
System.out.println(rs.getString(i));
237+
}
238+
}
239+
}
240+
}
241+
}
242+
```
243+
244+
## See also
245+
246+
[Azure Key vault sample version 7.0](../../connect/jdbc/azure-key-vault-sample-version-7.0.md)
247+
[Azure Key vault sample version 6.2.2](../../connect/jdbc/azure-key-vault-sample-version-6.2.2.md)
248+
[Azure Key vault sample version 6.0.0](../../connect/jdbc/azure-key-vault-sample-version-6.0.0.md)

0 commit comments

Comments
 (0)