From 12d5391686bb2795670d749a97b563e2da4f84d4 Mon Sep 17 00:00:00 2001 From: dauinsight <145612907+dauinsight@users.noreply.github.com> Date: Tue, 27 Aug 2024 14:56:09 -0700 Subject: [PATCH 01/12] Hotfix v5.1.6 Release notes (#2769) --- CHANGELOG.md | 15 ++++++++ release-notes/5.1/5.1.6.md | 75 +++++++++++++++++++++++++++++++++++++ release-notes/5.1/5.1.md | 1 + release-notes/5.1/README.md | 1 + 4 files changed, 92 insertions(+) create mode 100644 release-notes/5.1/5.1.6.md diff --git a/CHANGELOG.md b/CHANGELOG.md index 2432e91d68..b456bc7989 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -216,6 +216,21 @@ This update brings the below changes over the previous release: - Added Microsoft.SqlServer.Types to verify support for SqlHierarchyId and Spatial for .NET Core. [#1848](https://github.com/dotnet/SqlClient/pull/1848) - Code health improvements:[#1943](https://github.com/dotnet/SqlClient/pull/1943)[#1949](https://github.com/dotnet/SqlClient/pull/1949)[#1198](https://github.com/dotnet/SqlClient/pull/1198)[#1829](https://github.com/dotnet/SqlClient/pull/1829) +## [Stable release 5.1.6] - 2024-08-27 + +### Fixed + +- Fixed Transient fault handling issue with `OpenAsync`. [#1983](https://github.com/dotnet/SqlClient/pull/1983) [#2508](https://github.com/dotnet/SqlClient/pull/2508) +- Fixed `AcquireTokenAsync` timeout handling for edge cases in `ActiveDirectoryAuthenticationProvider`. [#2706](https://github.com/dotnet/SqlClient/pull/2706) +- Fixed pending data with `SqlDataReader` against an encrypted column. [#2618](https://github.com/dotnet/SqlClient/pull/2618) [#2818](https://github.com/dotnet/SqlClient/pull/2818) + +### Changed + +- Upgraded `Azure.Identity` version from 1.11.3 to 1.11.4 [#2649] (https://github.com/dotnet/SqlClient/pull/2649) [#2529] (https://github.com/dotnet/SqlClient/pull/2529) to address [CVE-2024-35255](https://github.com/advisories/GHSA-m5vv-6r4h-3vj9). +- Upgraded `Microsoft.Identity.Client` version from 4.60.0 to 4.61.3 [#2649] (https://github.com/dotnet/SqlClient/pull/2649) [#2529] (https://github.com/dotnet/SqlClient/pull/2529) to address [CVE-2024-35255](https://github.com/advisories/GHSA-m5vv-6r4h-3vj9). +- Added caching to `TokenCredential` objects to take advantage of token caching. [#2776](https://github.com/dotnet/SqlClient/pull/2776) +- Code health improvements: [#2490] (https://github.com/dotnet/SqlClient/pull/2490) + ## [Stable release 5.1.5] - 2024-01-29 This update brings the below changes over the previous release: diff --git a/release-notes/5.1/5.1.6.md b/release-notes/5.1/5.1.6.md new file mode 100644 index 0000000000..a5404c84da --- /dev/null +++ b/release-notes/5.1/5.1.6.md @@ -0,0 +1,75 @@ +# Release Notes + +## Microsoft.Data.SqlClient 5.1.6 released 27 August 2024 + +This update includes the following changes over the previous release: + +### Contributors +Thanks to the following public contributors. Their efforts toward this project are very much appreciated. + +### Fixed + +- Fixed Transient fault handling issue with `OpenAsync`. [#1983](https://github.com/dotnet/SqlClient/pull/1983) [#2508](https://github.com/dotnet/SqlClient/pull/2508) +- Fixed `AcquireTokenAsync` timeout handling for edge cases in `ActiveDirectoryAuthenticationProvider`. [#2706](https://github.com/dotnet/SqlClient/pull/2706) +- Fixed pending data with `SqlDataReader` against an encrypted column. [#2618](https://github.com/dotnet/SqlClient/pull/2618) [#2818](https://github.com/dotnet/SqlClient/pull/2818) + +### Changed + +- Upgraded `Azure.Identity` version from 1.11.3 to 1.11.4 [#2649] (https://github.com/dotnet/SqlClient/pull/2649) [#2529] (https://github.com/dotnet/SqlClient/pull/2529) to address [CVE-2024-35255](https://github.com/advisories/GHSA-m5vv-6r4h-3vj9). +- Upgraded `Microsoft.Identity.Client` version from 4.60.0 to 4.61.3 [#2649] (https://github.com/dotnet/SqlClient/pull/2649) [#2529] (https://github.com/dotnet/SqlClient/pull/2529) to address [CVE-2024-35255](https://github.com/advisories/GHSA-m5vv-6r4h-3vj9). +- Added caching to `TokenCredential` objects to take advantage of token caching. [#2776](https://github.com/dotnet/SqlClient/pull/2776) +- Code health improvements: [#2490] (https://github.com/dotnet/SqlClient/pull/2490) + +## Target Platform Support + +- .NET Framework 4.6.2+ (Windows x86, Windows x64) +- .NET 6.0+ (Windows x86, Windows x64, Windows ARM64, Windows ARM, Linux, macOS) +- .NET Standard 2.0+ (Windows x86, Windows x64, Windows ARM64, Windows ARM, Linux, macOS) + +### Dependencies + +#### .NET Framework + +- Microsoft.Data.SqlClient.SNI 5.1.1 +- Azure.Identity 1.11.4 +- Microsoft.Identity.Client 4.61.3 +- Microsoft.IdentityModel.JsonWebTokens 6.35.0 +- Microsoft.IdentityModel.Protocols.OpenIdConnect 6.35.0 +- System.Buffers 4.5.1 +- System.Configuration.ConfigurationManager 6.0.1 +- System.Runtime.InteropServices.RuntimeInformation 4.3.0 +- System.Text.Encodings.Web 6.0.0 + +#### .NET + +- Microsoft.Data.SqlClient.SNI.runtime 5.1.1 +- Azure.Identity 1.11.4 +- Microsoft.Identity.Client 4.61.3 +- Microsoft.IdentityModel.JsonWebTokens 6.35.0 +- Microsoft.IdentityModel.Protocols.OpenIdConnect 6.35.0 +- Microsoft.SqlServer.Server 1.0.0 +- System.Configuration.ConfigurationManager 6.0.1 +- System.Diagnostics.DiagnosticSource 6.0.0 +- System.Runtime.Caching 6.0.0 +- System.Text.Encoding.CodePages 6.0.0 +- System.Text.Encodings.Web 6.0.0 +- System.Security.Cryptography.Cng 5.0.0 +- System.Security.Principal.Windows 5.0.0 + +#### .NET Standard + +- Microsoft.Data.SqlClient.SNI.runtime 5.1.1 +- Azure.Identity 1.11.4 +- Microsoft.Identity.Client 4.61.3 +- Microsoft.IdentityModel.Protocols.OpenIdConnect 6.35.0 +- Microsoft.IdentityModel.JsonWebTokens 6.35.0 +- Microsoft.SqlServer.Server 1.0.0 +- Microsoft.Win32.Registry 5.0.0 +- System.Buffers 4.5.1 +- System.Configuration.ConfigurationManager 6.0.1 +- System.Runtime.Caching 6.0.0 +- System.Text.Encoding.CodePages 6.0.0 +- System.Text.Encodings.Web 6.0.0 +- System.Runtime.Loader 4.3.0 +- System.Security.Cryptography.Cng 5.0.0 +- System.Security.Principal.Windows 5.0.0 diff --git a/release-notes/5.1/5.1.md b/release-notes/5.1/5.1.md index 09b83805c2..99db6d4c58 100644 --- a/release-notes/5.1/5.1.md +++ b/release-notes/5.1/5.1.md @@ -4,6 +4,7 @@ The following Microsoft.Data.SqlClient 5.1 stable releases have been shipped: | Release Date | Version | Notes | | :-- | :-- | :--: | +| 2024/08/27 | 5.1.6 | [release notes](5.1.6.md) | | 2024/01/29 | 5.1.5 | [release notes](5.1.5.md) | | 2024/01/09 | 5.1.4 | [release notes](5.1.4.md) | | 2024/01/09 | 5.1.3 | [release notes](5.1.3.md) | diff --git a/release-notes/5.1/README.md b/release-notes/5.1/README.md index 09b83805c2..99db6d4c58 100644 --- a/release-notes/5.1/README.md +++ b/release-notes/5.1/README.md @@ -4,6 +4,7 @@ The following Microsoft.Data.SqlClient 5.1 stable releases have been shipped: | Release Date | Version | Notes | | :-- | :-- | :--: | +| 2024/08/27 | 5.1.6 | [release notes](5.1.6.md) | | 2024/01/29 | 5.1.5 | [release notes](5.1.5.md) | | 2024/01/09 | 5.1.4 | [release notes](5.1.4.md) | | 2024/01/09 | 5.1.3 | [release notes](5.1.3.md) | From c223dfb9c301812a4a73cad80d9f3c15d58c6a9b Mon Sep 17 00:00:00 2001 From: dauinsight <145612907+dauinsight@users.noreply.github.com> Date: Tue, 27 Aug 2024 15:48:48 -0700 Subject: [PATCH 02/12] Hotfix v5.2.2 Release notes (#2770) --- CHANGELOG.md | 17 ++++++ release-notes/5.2/5.2.2.md | 100 ++++++++++++++++++++++++++++++++++++ release-notes/5.2/5.2.md | 1 + release-notes/5.2/README.md | 1 + 4 files changed, 119 insertions(+) create mode 100644 release-notes/5.2/5.2.2.md diff --git a/CHANGELOG.md b/CHANGELOG.md index b456bc7989..bcb1f760bd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,23 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) +## [Stable release 5.2.2] - 2024-08-27 + +### Fixed + +- Fixed `AcquireTokenAsync` timeout handling for edge cases in `ActiveDirectoryAuthenticationProvider`. [#2650](https://github.com/dotnet/SqlClient/pull/2650) +- Fixed issue with `Socket.Connect` in managed SNI. [#2779](https://github.com/dotnet/SqlClient/pull/2779) +- Fixed path for `AssemblyAttributes` in obj folder causing NET 8.0 assembly to appear in NET 6.0 dll. [#2789](https://github.com/dotnet/SqlClient/pull/2789) +- Fixed SSPI retry negotiation with default port in .NET. [#2815](https://github.com/dotnet/SqlClient/pull/2815) +- Fixed `ArgumentNullException` on `SqlDataRecord.GetValue` when using user-defined data type on .NET. [#2816](https://github.com/dotnet/SqlClient/pull/2816) +- Fixed pending data with `SqlDataReader` against an encrypted column. [#2817](https://github.com/dotnet/SqlClient/pull/2817) + +### Changed + +- Upgraded `Azure.Identity` version from 1.11.3 to 1.11.4 [#2648](https://github.com/dotnet/SqlClient/pull/2648) to address [CVE-2024-35255](https://github.com/advisories/GHSA-m5vv-6r4h-3vj9). +- Upgraded `Microsoft.Identity.Client` version from 4.60.0 to 4.61.3 [#2648](https://github.com/dotnet/SqlClient/pull/2648) to address [CVE-2024-35255](https://github.com/advisories/GHSA-m5vv-6r4h-3vj9). +- Added caching to `TokenCredential` objects to take advantage of token caching. [#2775](https://github.com/dotnet/SqlClient/pull/2775) + ## [Stable release 5.2.1] - 2024-05-31 This update brings the below changes over the previous release: diff --git a/release-notes/5.2/5.2.2.md b/release-notes/5.2/5.2.2.md new file mode 100644 index 0000000000..1947d5f373 --- /dev/null +++ b/release-notes/5.2/5.2.2.md @@ -0,0 +1,100 @@ +# Release Notes + +## [Stable release 5.2.2] - 2024-08-27 + +This update brings the below changes over the previous release: + +### Fixed + +- Fixed `AcquireTokenAsync` timeout handling for edge cases in `ActiveDirectoryAuthenticationProvider`. [#2650](https://github.com/dotnet/SqlClient/pull/2650) +- Fixed issue with `Socket.Connect` in managed SNI. [#2779](https://github.com/dotnet/SqlClient/pull/2779) +- Fixed path for `AssemblyAttributes` in obj folder causing NET 8.0 assembly to appear in NET 6.0 dll. [#2789](https://github.com/dotnet/SqlClient/pull/2789) +- Fixed SSPI retry negotiation with default port in .NET. [#2815](https://github.com/dotnet/SqlClient/pull/2815) +- Fixed `ArgumentNullException` on `SqlDataRecord.GetValue` when using user-defined data type on .NET. [#2816](https://github.com/dotnet/SqlClient/pull/2816) +- Fixed pending data with `SqlDataReader` against an encrypted column. [#2817](https://github.com/dotnet/SqlClient/pull/2817) + +### Changed + +- Upgraded `Azure.Identity` version from 1.11.3 to 1.11.4 [#2648](https://github.com/dotnet/SqlClient/pull/2648) to address [CVE-2024-35255](https://github.com/advisories/GHSA-m5vv-6r4h-3vj9). +- Upgraded `Microsoft.Identity.Client` version from 4.60.0 to 4.61.3 [#2648](https://github.com/dotnet/SqlClient/pull/2648) to address [CVE-2024-35255](https://github.com/advisories/GHSA-m5vv-6r4h-3vj9). +- Added caching to `TokenCredential` objects to take advantage of token caching. [#2775](https://github.com/dotnet/SqlClient/pull/2775) + +## Target Platform Support + +- .NET Framework 4.6.2+ (Windows x86, Windows x64) +- .NET 6.0+ (Windows x86, Windows x64, Windows ARM64, Windows ARM, Linux, macOS) +- .NET Standard 2.0+ (Windows x86, Windows x64, Windows ARM64, Windows ARM, Linux, macOS) + +### Dependencies + +#### .NET Framework + +- Microsoft.Data.SqlClient.SNI 5.2.0 +- Azure.Identity 1.11.4 +- Microsoft.Identity.Client 4.61.3 +- Microsoft.IdentityModel.Protocols.OpenIdConnect 6.35.0 +- Microsoft.IdentityModel.JsonWebTokens 6.35.0 +- System.Buffers 4.5.1 +- System.Configuration.ConfigurationManager 6.0.1 +- System.Runtime.InteropServices.RuntimeInformation 4.3.0 +- System.Text.Encodings.Web 6.0.0 + +#### .NET 6 + +- Microsoft.Data.SqlClient.SNI.runtime 5.2.0 +- Azure.Identity 1.11.4 +- Microsoft.Identity.Client 4.61.3 +- Microsoft.IdentityModel.Protocols.OpenIdConnect 6.35.0 +- Microsoft.IdentityModel.JsonWebTokens 6.35.0 +- Microsoft.SqlServer.Server 1.0.0 +- System.Configuration.ConfigurationManager 6.0.1 +- System.Runtime.Caching 6.0.0 + +#### .NET 8 + +- Microsoft.Data.SqlClient.SNI.runtime 5.2.0 +- Azure.Identity 1.11.4 +- Microsoft.Identity.Client 4.61.3 +- Microsoft.IdentityModel.Protocols.OpenIdConnect 6.35.0 +- Microsoft.IdentityModel.JsonWebTokens 6.35.0 +- Microsoft.SqlServer.Server 1.0.0 +- System.Configuration.ConfigurationManager 8.0.0 +- System.Runtime.Caching 8.0.0 + +#### .NET Standard 2.0 + +- Microsoft.Data.SqlClient.SNI.runtime 5.2.0 +- Azure.Identity 1.11.4 +- Microsoft.Identity.Client 4.61.3 +- Microsoft.IdentityModel.Protocols.OpenIdConnect 6.35.0 +- Microsoft.IdentityModel.JsonWebTokens 6.35.0 +- Microsoft.SqlServer.Server 1.0.0 +- Microsoft.Win32.Registry 5.0.0 +- System.Buffers 4.5.1 +- System.Configuration.ConfigurationManager 6.0.1 +- System.Diagnostics.DiagnosticSource 6.0.1 +- System.Runtime.Caching 6.0.0 +- System.Text.Encoding.CodePages 6.0.0 +- System.Text.Encodings.Web 6.0.0 +- System.Runtime.Loader 4.3.0 +- System.Security.Cryptography.Cng 5.0.0 +- System.Security.Principal.Windows 5.0.0 + +#### .NET Standard 2.1 + +- Microsoft.Data.SqlClient.SNI.runtime 5.2.0 +- Azure.Identity 1.11.4 +- Microsoft.Identity.Client 4.61.3 +- Microsoft.IdentityModel.Protocols.OpenIdConnect 6.35.0 +- Microsoft.IdentityModel.JsonWebTokens 6.35.0 +- Microsoft.SqlServer.Server 1.0.0 +- Microsoft.Win32.Registry 5.0.0 +- System.Configuration.ConfigurationManager 6.0.1 +- System.Diagnostics.DiagnosticSource 6.0.1 +- System.Runtime.Caching 6.0.0 +- System.Text.Encoding.CodePages 6.0.0 +- System.Text.Encodings.Web 6.0.0 +- System.Runtime.Loader 4.3.0 +- System.Security.Cryptography.Cng 5.0.0 +- System.Security.Principal.Windows 5.0.0 + diff --git a/release-notes/5.2/5.2.md b/release-notes/5.2/5.2.md index 18473289b3..e94144af62 100644 --- a/release-notes/5.2/5.2.md +++ b/release-notes/5.2/5.2.md @@ -4,6 +4,7 @@ The following Microsoft.Data.SqlClient 5.2 stable releases have been shipped: | Release Date | Version | Notes | | :-- | :-- | :--: | +| 2024/08/27 | 5.2.2 | [release notes](5.2.2.md) | | 2024/05/31 | 5.2.1 | [release notes](5.2.1.md) | | 2024/02/28 | 5.2.0 | [release notes](5.2.0.md) | diff --git a/release-notes/5.2/README.md b/release-notes/5.2/README.md index 1d5a27bb00..ed6f4a377a 100644 --- a/release-notes/5.2/README.md +++ b/release-notes/5.2/README.md @@ -4,6 +4,7 @@ The following Microsoft.Data.SqlClient 5.2 stable releases have been shipped: | Release Date | Version | Notes | | :-- | :-- | :--: | +| 2024/08/27 | 5.2.2 | [release notes](5.2.2.md) | | 2024/05/31 | 5.2.1 | [release notes](5.2.1.md) | | 2024/02/28 | 5.2.0 | [release notes](5.2.0.md) | From 5ea0e25d68b18e14e4446bd783fb91c4bc7cdf19 Mon Sep 17 00:00:00 2001 From: David Engel Date: Tue, 27 Aug 2024 16:24:24 -0700 Subject: [PATCH 03/12] Add porting information about NLS to ICU .NET 5+ change (#2820) --- porting-cheat-sheet.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/porting-cheat-sheet.md b/porting-cheat-sheet.md index d09c16c77e..f0c4dc584f 100644 --- a/porting-cheat-sheet.md +++ b/porting-cheat-sheet.md @@ -53,6 +53,12 @@ For .NET Framework projects it may be necessary to include the following in your | Using DateTime object as value for SqlParameter with type `DbType.Date` would send date and time to SQL Server. | DateTime object's time components will be truncated when sent to SQL Server using `DbType.Date`. | | `Encrypt` defaults to `false`. | Starting in v4.0, default encryption settings were made more secure, requiring opt-in to non-encrypted connections. `Encrypt` defaults to `true` and the driver will always validate the server certificate based on `TrustServerCertificate`. (Previously, server certificates would only be validated if `Encrypt` was also `true`.)

If you need to turn off encryption, you must specify `Encrypt=false`. If you use encryption with a self-signed certificate on the server, you must specify `TrustServerCertificate=true`.

In v5.0, `SqlConnectionStringBuilder.Encrypt` is no longer a `bool`. It's a `SqlConnectionEncryptOption` with multiple values to support `Strict` encryption mode (TDS 8.0). It uses implicit conversion operators to remain code-backwards compatible, but it was a binary breaking change, requiring a recompile of applications. | +## .NET Framework to .NET Considerations + +In .NET Framework and .NET versions prior to .NET 5, globalization APIs use National Language Support (NLS) on Windows. Starting in .NET 5, .NET globalization APIs changed to use International Components for Unicode (ICU) on Windows in order to be consistent across all platforms (Windows, Linux, macOS, etc.). This affects the behavior of comparisons of some SqlStrings in System.Data.SqlTypes. Comparisons using ICU don't always match NLS for some strings. Since SQL Server still uses NLS on the server side for string comparisons, this difference can result in SqlString comparisons behaving differently than server side string comparisons. If your application relies on SqlString behavior matching server side behavior, you need to resolve this issue. For detailed information in .NET, see [Globalization and ICU](https://learn.microsoft.com/en-us/dotnet/core/extensions/globalization-icu). + +If your application is affected, the workaround is to [Use NLS instead of ICU](https://learn.microsoft.com/en-us/dotnet/core/extensions/globalization-icu#use-nls-instead-of-icu) in your application. + ## Contribute to this Cheat Sheet We would love the SqlClient community to help enhance this cheat sheet by contributing experiences and challenges faced when porting their applications. From 9573da26fbab3de0ab75110f769b3c5b2f55199a Mon Sep 17 00:00:00 2001 From: DavoudEshtehari <61173489+DavoudEshtehari@users.noreply.github.com> Date: Wed, 28 Aug 2024 10:51:41 -0700 Subject: [PATCH 04/12] Doc | Release notes v6.0 preview1 (#2813) --- CHANGELOG.md | 51 ++++++++++++++ release-notes/6.0/6.0.0-preview1.md | 100 ++++++++++++++++++++++++++++ release-notes/6.0/6.0.md | 7 ++ release-notes/6.0/README.md | 7 ++ 4 files changed, 165 insertions(+) create mode 100644 release-notes/6.0/6.0.0-preview1.md create mode 100644 release-notes/6.0/6.0.md create mode 100644 release-notes/6.0/README.md diff --git a/CHANGELOG.md b/CHANGELOG.md index bcb1f760bd..bad4582353 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,57 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) +## [Preview Release 6.0.0-preview1.24240.8] - 2024-08-27 + +This update brings the below changes over the previous release: + +### Breaking Changes + +- Removed support for .NET Standard. [#2386](https://github.com/dotnet/SqlClient/pull/2386) +- Removed UWP (uap) references. [#2483](https://github.com/dotnet/SqlClient/pull/2483) + +### Added + +- Added `TokenCredential` object to take advantage of token caching in `ActiveDirectoryAuthenticationProvider`. [#2380](https://github.com/dotnet/SqlClient/pull/2380) +- Added `DateOnly` and `TimeOnly` support to `DataTable` as a structured parameter. [#2258](https://github.com/dotnet/SqlClient/pull/2258) +- Added `Microsoft.Data.SqlClient.Diagnostics.SqlClientDiagnostic` type in .NET. [#2226](https://github.com/dotnet/SqlClient/pull/2226) +- Added scope trace for `GenerateSspiClientContext`. [#2497](https://github.com/dotnet/SqlClient/pull/2497), [#2725](https://github.com/dotnet/SqlClient/pull/2725) + +### Fixed + +- Fixed `Socket.Connect` timeout issue caused by thread starvation. [#2777](https://github.com/dotnet/SqlClient/pull/2777) +- Fixed pending data with `SqlDataReader` against an encrypted column. [#2618](https://github.com/dotnet/SqlClient/pull/2618) +- Fixed Entra authentication when using infinite connection timeout in `ActiveDirectoryAuthenticationProvider`. [#2651](https://github.com/dotnet/SqlClient/pull/2651) +- Fixed `GetSchema` by excluding unsupported engines due to lack of support for `ASSEMBLYPROPERTY` function. [#2593](https://github.com/dotnet/SqlClient/pull/2593) +- Fixed SSPI retry negotiation with default port in .NET. [#2559](https://github.com/dotnet/SqlClient/pull/2559) +- Fixed assembly path in .NET 8.0 and `.AssemblyAttributes`. [#2550](https://github.com/dotnet/SqlClient/pull/2550) +- Fixed certificate chain validation. [#2487](https://github.com/dotnet/SqlClient/pull/2487) +- Fixed clone of `SqlConnection` to include `AccessTokenCallback`. [#2525](https://github.com/dotnet/SqlClient/pull/2525) +- Fixed issue with `DateTimeOffset` in table-valued parameters, which was introduced in 5.2. [#2453](https://github.com/dotnet/SqlClient/pull/2453) +- Fixed `ArgumentNullException` on `SqlDataRecord.GetValue` when using user-defined data type on .NET. [#2448](https://github.com/dotnet/SqlClient/pull/2448) +- Fixed `SqlBuffer` and `SqlGuild` when it's null. [#2310](https://github.com/dotnet/SqlClient/pull/2310) +- Fixed `SqlBulkCopy.WriteToServer` state in a consecutive calls. [#2375](https://github.com/dotnet/SqlClient/pull/2375) +- Fixed null reference exception with `SqlConnection.FireInfoMessageEventOnUserErrors` after introducing the batch command. [#2399](https://github.com/dotnet/SqlClient/pull/2399) + +### Changed + +- Updated Microsoft.Data.SqlClient.SNI version to `6.0.0-preview1.24226.4`. [#2772](https://github.com/dotnet/SqlClient/pull/2772) +- Improved access to `SqlAuthenticationProviderManager.Instance` and avoid early object initiation. [#2636](https://github.com/dotnet/SqlClient/pull/2636) +- Removed undocumented properties of `Azure.Identity` in `ActiveDirectoryAuthenticationProvider`. [#2562](https://github.com/dotnet/SqlClient/pull/2562) +- Replaced `System.Runtime.Caching` with `Microsoft.Extensions.Caching.Memory`. [#2493](https://github.com/dotnet/SqlClient/pull/2493) +- Updated `EnableOptimizedParameterBinding` to only accept text mode commands. [#2417](https://github.com/dotnet/SqlClient/pull/2417) +- Updated `Azure.Identity` version from `1.10.3` to `1.11.4`. [#2577](https://github.com/dotnet/SqlClient/pull/2577) +- Updated `Azure.Core` version from `1.35.0` to `1.38.0`. [#2462](https://github.com/dotnet/SqlClient/pull/2462) +- Updated `Azure.Security.KeyVault.Keys` version from `4.4.0` to `4.5.0`. [#2462](https://github.com/dotnet/SqlClient/pull/2462) +- Updated `Microsoft.IdentityModel.JsonWebTokens` and `Microsoft.IdentityModel.Protocols.OpenIdConnect` from `6.35.0` to `7.5.0`. [#2429](https://github.com/dotnet/SqlClient/pull/2429) +- Removed direct dependency to `Microsoft.Identity.Client` to take the transient dependecy through `Azure.Identity`. [#2577](https://github.com/dotnet/SqlClient/pull/2577) +- Removed unnecessary references `Microsoft.Extensions.Caching.Memory` and `System.Security.Cryptography.Cng` after removing .NET Standard. [#2577](https://github.com/dotnet/SqlClient/pull/2577) +- Improved memory allocation when reader opened by `CommandBehavior.SequentialAccess` over the big string columns. [#2356](https://github.com/dotnet/SqlClient/pull/2356) +- Improved SSPI by consolidating the context generation to single abstraction and using memory/span for SSPI generation. [#2255](https://github.com/dotnet/SqlClient/pull/2255), [#2447](https://github.com/dotnet/SqlClient/pull/2447) +- Reverted the [#2281](https://github.com/dotnet/SqlClient/pull/2281) code changes on ManagedSNI. [#2395](https://github.com/dotnet/SqlClient/pull/2395) +- Updated assembly version to 6.0.0.0. [#2382](https://github.com/dotnet/SqlClient/pull/2382) +- Code health improvements: [#2366](https://github.com/dotnet/SqlClient/pull/2366), [#2369](https://github.com/dotnet/SqlClient/pull/2369), [#2381](https://github.com/dotnet/SqlClient/pull/2381), [#2390](https://github.com/dotnet/SqlClient/pull/2390), [#2392](https://github.com/dotnet/SqlClient/pull/2392), [#2403](https://github.com/dotnet/SqlClient/pull/2403), [#2410](https://github.com/dotnet/SqlClient/pull/2410), [#2413](https://github.com/dotnet/SqlClient/pull/2413), [#2425](https://github.com/dotnet/SqlClient/pull/2425), [#2428](https://github.com/dotnet/SqlClient/pull/2428), [#2440](https://github.com/dotnet/SqlClient/pull/2440), [#2443](https://github.com/dotnet/SqlClient/pull/2443), [#2450](https://github.com/dotnet/SqlClient/pull/2450), [#2466](https://github.com/dotnet/SqlClient/pull/2466), [#2486](https://github.com/dotnet/SqlClient/pull/2486), [#2521](https://github.com/dotnet/SqlClient/pull/2521), [#2522](https://github.com/dotnet/SqlClient/pull/2522), [#2533](https://github.com/dotnet/SqlClient/pull/2533), [#2552](https://github.com/dotnet/SqlClient/pull/2552), [#2560](https://github.com/dotnet/SqlClient/pull/2560), [#2726](https://github.com/dotnet/SqlClient/pull/2726), [#2751](https://github.com/dotnet/SqlClient/pull/2751), [#2811](https://github.com/dotnet/SqlClient/pull/2811) + ## [Stable release 5.2.2] - 2024-08-27 ### Fixed diff --git a/release-notes/6.0/6.0.0-preview1.md b/release-notes/6.0/6.0.0-preview1.md new file mode 100644 index 0000000000..86589346d8 --- /dev/null +++ b/release-notes/6.0/6.0.0-preview1.md @@ -0,0 +1,100 @@ +# Release Notes + +## [Preview Release 6.0.0-preview1.24240.8] - 2024-08-27 + +This update brings the below changes over the previous release: + +### Contributors +Thanks to the following public contributors. Their efforts toward this project are very much appreciated. + +- [ErikEJ](https://github.com/ErikEJ) +- [edwardneal](https://github.com/edwardneal) +- [Wraith2](https://github.com/Wraith2) +- [twsouthwick](https://github.com/twsouthwick) +- [0xced](https://github.com/0xced) +- [wilbit](https://github.com/wilbit) +- [TrayanZapryanov](https://github.com/TrayanZapryanov) + +### Breaking Changes + +- Removed support for .NET Standard. [#2386](https://github.com/dotnet/SqlClient/pull/2386) +- Removed UWP (uap) references. [#2483](https://github.com/dotnet/SqlClient/pull/2483) + +### Added + +- Added `TokenCredential` object to take advantage of token caching in `ActiveDirectoryAuthenticationProvider`. [#2380](https://github.com/dotnet/SqlClient/pull/2380) +- Added `DateOnly` and `TimeOnly` support to `DataTable` as a structured parameter. [#2258](https://github.com/dotnet/SqlClient/pull/2258) +- Added `Microsoft.Data.SqlClient.Diagnostics.SqlClientDiagnostic` type in .NET. [#2226](https://github.com/dotnet/SqlClient/pull/2226) +- Added scope trace for `GenerateSspiClientContext`. [#2497](https://github.com/dotnet/SqlClient/pull/2497), [#2725](https://github.com/dotnet/SqlClient/pull/2725) + +### Fixed + +- Fixed `Socket.Connect` timeout issue caused by thread starvation. [#2777](https://github.com/dotnet/SqlClient/pull/2777) +- Fixed pending data with `SqlDataReader` against an encrypted column. [#2618](https://github.com/dotnet/SqlClient/pull/2618) +- Fixed Entra authentication when using infinite connection timeout in `ActiveDirectoryAuthenticationProvider`. [#2651](https://github.com/dotnet/SqlClient/pull/2651) +- Fixed `GetSchema` by excluding unsupported engines due to lack of support for `ASSEMBLYPROPERTY` function. [#2593](https://github.com/dotnet/SqlClient/pull/2593) +- Fixed SSPI retry negotiation with default port in .NET. [#2559](https://github.com/dotnet/SqlClient/pull/2559) +- Fixed assembly path in .NET 8.0 and `.AssemblyAttributes`. [#2550](https://github.com/dotnet/SqlClient/pull/2550) +- Fixed certificate chain validation. [#2487](https://github.com/dotnet/SqlClient/pull/2487) +- Fixed clone of `SqlConnection` to include `AccessTokenCallback`. [#2525](https://github.com/dotnet/SqlClient/pull/2525) +- Fixed issue with `DateTimeOffset` in table-valued parameters, which was introduced in 5.2. [#2453](https://github.com/dotnet/SqlClient/pull/2453) +- Fixed `ArgumentNullException` on `SqlDataRecord.GetValue` when using user-defined data type on .NET. [#2448](https://github.com/dotnet/SqlClient/pull/2448) +- Fixed `SqlBuffer` and `SqlGuild` when it's null. [#2310](https://github.com/dotnet/SqlClient/pull/2310) +- Fixed `SqlBulkCopy.WriteToServer` state in a consecutive calls. [#2375](https://github.com/dotnet/SqlClient/pull/2375) +- Fixed null reference exception with `SqlConnection.FireInfoMessageEventOnUserErrors` after introducing the batch command. [#2399](https://github.com/dotnet/SqlClient/pull/2399) + +### Changed + +- Updated Microsoft.Data.SqlClient.SNI version to `6.0.0-preview1.24226.4`. [#2772](https://github.com/dotnet/SqlClient/pull/2772) +- Improved access to `SqlAuthenticationProviderManager.Instance` and avoid early object initiation. [#2636](https://github.com/dotnet/SqlClient/pull/2636) +- Removed undocumented properties of `Azure.Identity` in `ActiveDirectoryAuthenticationProvider`. [#2562](https://github.com/dotnet/SqlClient/pull/2562) +- Replaced `System.Runtime.Caching` with `Microsoft.Extensions.Caching.Memory`. [#2493](https://github.com/dotnet/SqlClient/pull/2493) +- Updated `EnableOptimizedParameterBinding` to only accept text mode commands. [#2417](https://github.com/dotnet/SqlClient/pull/2417) +- Updated `Azure.Identity` version from `1.10.3` to `1.11.4`. [#2577](https://github.com/dotnet/SqlClient/pull/2577) +- Updated `Azure.Core` version from `1.35.0` to `1.38.0`. [#2462](https://github.com/dotnet/SqlClient/pull/2462) +- Updated `Azure.Security.KeyVault.Keys` version from `4.4.0` to `4.5.0`. [#2462](https://github.com/dotnet/SqlClient/pull/2462) +- Updated `Microsoft.IdentityModel.JsonWebTokens` and `Microsoft.IdentityModel.Protocols.OpenIdConnect` from `6.35.0` to `7.5.0`. [#2429](https://github.com/dotnet/SqlClient/pull/2429) +- Removed direct dependency to `Microsoft.Identity.Client` to take the transient dependecy through `Azure.Identity`. [#2577](https://github.com/dotnet/SqlClient/pull/2577) +- Removed unnecessary references `Microsoft.Extensions.Caching.Memory` and `System.Security.Cryptography.Cng` after removing .NET Standard. [#2577](https://github.com/dotnet/SqlClient/pull/2577) +- Improved memory allocation when reader opened by `CommandBehavior.SequentialAccess` over the big string columns. [#2356](https://github.com/dotnet/SqlClient/pull/2356) +- Improved SSPI by consolidating the context generation to single abstraction and using memory/span for SSPI generation. [#2255](https://github.com/dotnet/SqlClient/pull/2255), [#2447](https://github.com/dotnet/SqlClient/pull/2447) +- Reverted the [#2281](https://github.com/dotnet/SqlClient/pull/2281) code changes on ManagedSNI. [#2395](https://github.com/dotnet/SqlClient/pull/2395) +- Updated assembly version to 6.0.0.0. [#2382](https://github.com/dotnet/SqlClient/pull/2382) +- Code health improvements: [#2366](https://github.com/dotnet/SqlClient/pull/2366), [#2369](https://github.com/dotnet/SqlClient/pull/2369), [#2381](https://github.com/dotnet/SqlClient/pull/2381), [#2390](https://github.com/dotnet/SqlClient/pull/2390), [#2392](https://github.com/dotnet/SqlClient/pull/2392), [#2403](https://github.com/dotnet/SqlClient/pull/2403), [#2410](https://github.com/dotnet/SqlClient/pull/2410), [#2413](https://github.com/dotnet/SqlClient/pull/2413), [#2425](https://github.com/dotnet/SqlClient/pull/2425), [#2428](https://github.com/dotnet/SqlClient/pull/2428), [#2440](https://github.com/dotnet/SqlClient/pull/2440), [#2443](https://github.com/dotnet/SqlClient/pull/2443), [#2450](https://github.com/dotnet/SqlClient/pull/2450), [#2466](https://github.com/dotnet/SqlClient/pull/2466), [#2486](https://github.com/dotnet/SqlClient/pull/2486), [#2521](https://github.com/dotnet/SqlClient/pull/2521), [#2522](https://github.com/dotnet/SqlClient/pull/2522), [#2533](https://github.com/dotnet/SqlClient/pull/2533), [#2552](https://github.com/dotnet/SqlClient/pull/2552), [#2560](https://github.com/dotnet/SqlClient/pull/2560), [#2726](https://github.com/dotnet/SqlClient/pull/2726), [#2751](https://github.com/dotnet/SqlClient/pull/2751), [#2811](https://github.com/dotnet/SqlClient/pull/2811) + +## Target Platform Support + +- .NET Framework 4.6.2+ (Windows x86, Windows x64) +- .NET 6.0+ (Windows x86, Windows x64, Windows ARM64, Windows ARM, Linux, macOS) + +### Dependencies + +#### .NET Framework + +- Microsoft.Data.SqlClient.SNI 6.0.0-preview1.24226.4 +- Azure.Identity 1.11.4 +- Microsoft.Extensions.Caching.Memory 6.0.1 +- Microsoft.IdentityModel.JsonWebTokens 7.5.0 +- Microsoft.IdentityModel.Protocols.OpenIdConnect 7.5.0 +- System.Buffers 4.5.1 +- System.Text.Encodings.Web 6.0.0 + +#### .NET 6 + +- Microsoft.Data.SqlClient.SNI.runtime 6.0.0-preview1.24226.4 +- Azure.Identity 1.11.4 +- Microsoft.Extensions.Caching.Memory 6.0.1 +- Microsoft.IdentityModel.JsonWebTokens 7.5.0 +- Microsoft.IdentityModel.Protocols.OpenIdConnect 7.5.0 +- Microsoft.SqlServer.Server 1.0.0 +- System.Configuration.ConfigurationManager 6.0.1 + +#### .NET 8 + +- Microsoft.Data.SqlClient.SNI.runtime 6.0.0-preview1.24226.4 +- Azure.Identity 1.11.4 +- Microsoft.Extensions.Caching.Memory 8.0.0 +- Microsoft.IdentityModel.JsonWebTokens 7.5.0 +- Microsoft.IdentityModel.Protocols.OpenIdConnect 7.5.0 +- Microsoft.SqlServer.Server 1.0.0 +- System.Configuration.ConfigurationManager 8.0.0 diff --git a/release-notes/6.0/6.0.md b/release-notes/6.0/6.0.md new file mode 100644 index 0000000000..83272ac61d --- /dev/null +++ b/release-notes/6.0/6.0.md @@ -0,0 +1,7 @@ +# Microsoft.Data.SqlClient 6.0 Releases + +The following Microsoft.Data.SqlClient 6.0 preview releases have been shipped: + +| Release Date | Version | Notes | +| :-- | :-- | :--: | +| 2024-08-27 | 6.0.0-preview1.24240.8 | [release notes](6.0.0-preview1.md) | diff --git a/release-notes/6.0/README.md b/release-notes/6.0/README.md new file mode 100644 index 0000000000..83272ac61d --- /dev/null +++ b/release-notes/6.0/README.md @@ -0,0 +1,7 @@ +# Microsoft.Data.SqlClient 6.0 Releases + +The following Microsoft.Data.SqlClient 6.0 preview releases have been shipped: + +| Release Date | Version | Notes | +| :-- | :-- | :--: | +| 2024-08-27 | 6.0.0-preview1.24240.8 | [release notes](6.0.0-preview1.md) | From aa0db93336511390b9e389123f25a5ae74e55c62 Mon Sep 17 00:00:00 2001 From: Aris Rellegue <134557572+arellegue@users.noreply.github.com> Date: Thu, 29 Aug 2024 17:59:42 +0000 Subject: [PATCH 05/12] Test | Fix Unit Tests for GetSqlServerSPN (#2442) --- .../ManualTests/DataCommon/DataTestUtility.cs | 3 + ....Data.SqlClient.ManualTesting.Tests.csproj | 1 + .../DataSourceParserTest.cs | 75 +++++++++++++++++++ .../SQL/InstanceNameTest/InstanceNameTest.cs | 59 +++++++++++---- 4 files changed, 123 insertions(+), 15 deletions(-) create mode 100644 src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/DataSourceParserTest/DataSourceParserTest.cs diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/DataTestUtility.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/DataTestUtility.cs index 0a32356fe9..9e69b7a39f 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/DataTestUtility.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/DataTestUtility.cs @@ -952,6 +952,9 @@ public static bool ParseDataSource(string dataSource, out string hostname, out i port = -1; instanceName = string.Empty; + // Remove leading and trailing spaces + dataSource = dataSource.Trim(); + if (dataSource.Contains(":")) { dataSource = dataSource.Substring(dataSource.IndexOf(":", StringComparison.Ordinal) + 1); diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/Microsoft.Data.SqlClient.ManualTesting.Tests.csproj b/src/Microsoft.Data.SqlClient/tests/ManualTests/Microsoft.Data.SqlClient.ManualTesting.Tests.csproj index 7a3dad589d..0ec61b5420 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/Microsoft.Data.SqlClient.ManualTesting.Tests.csproj +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/Microsoft.Data.SqlClient.ManualTesting.Tests.csproj @@ -179,6 +179,7 @@ + diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/DataSourceParserTest/DataSourceParserTest.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/DataSourceParserTest/DataSourceParserTest.cs new file mode 100644 index 0000000000..38d4685537 --- /dev/null +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/DataSourceParserTest/DataSourceParserTest.cs @@ -0,0 +1,75 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Xunit; + +namespace Microsoft.Data.SqlClient.ManualTesting.Tests.SQL.DataSourceParserTest +{ + public class DataSourceParserTest + { + [ConditionalTheory(typeof(DataTestUtility), nameof(DataTestUtility.IsNotAzureServer), nameof(DataTestUtility.IsNotAzureSynapse))] + [InlineData("localhost")] + [InlineData("tcp:localhost")] + [InlineData(" localhost ")] + [InlineData(" tcp:localhost ")] + [InlineData(" localhost")] + [InlineData(" tcp:localhost")] + [InlineData("localhost ")] + [InlineData("tcp:localhost ")] + public void ParseDataSourceWithoutInstanceNorPortTestShouldSucceed(string dataSource) + { + DataTestUtility.ParseDataSource(dataSource, out string hostname, out _, out _); + Assert.Equal("localhost", hostname); + } + + [ConditionalTheory(typeof(DataTestUtility), nameof(DataTestUtility.IsNotAzureServer), nameof(DataTestUtility.IsNotAzureSynapse))] + [InlineData("localhost,1433")] + [InlineData("tcp:localhost,1433")] + [InlineData(" localhost,1433 ")] + [InlineData(" tcp:localhost,1433 ")] + [InlineData(" localhost,1433")] + [InlineData(" tcp:localhost,1433")] + [InlineData("localhost,1433 ")] + [InlineData("tcp:localhost,1433 ")] + public void ParseDataSourceWithoutInstanceButWithPortTestShouldSucceed(string dataSource) + { + DataTestUtility.ParseDataSource(dataSource, out string hostname, out int port, out _); + Assert.Equal("localhost", hostname); + Assert.Equal(1433, port); + } + + [ConditionalTheory(typeof(DataTestUtility), nameof(DataTestUtility.IsNotAzureServer), nameof(DataTestUtility.IsNotAzureSynapse))] + [InlineData("localhost\\MSSQLSERVER02")] + [InlineData("tcp:localhost\\MSSQLSERVER02")] + [InlineData(" localhost\\MSSQLSERVER02 ")] + [InlineData(" tcp:localhost\\MSSQLSERVER02 ")] + [InlineData(" localhost\\MSSQLSERVER02")] + [InlineData(" tcp:localhost\\MSSQLSERVER02")] + [InlineData("localhost\\MSSQLSERVER02 ")] + [InlineData("tcp:localhost\\MSSQLSERVER02 ")] + public void ParseDataSourceWithInstanceButWithoutPortTestShouldSucceed(string dataSource) + { + DataTestUtility.ParseDataSource(dataSource, out string hostname, out _, out string instanceName); + Assert.Equal("localhost", hostname); + Assert.Equal("MSSQLSERVER02", instanceName); + } + + [ConditionalTheory(typeof(DataTestUtility), nameof(DataTestUtility.IsNotAzureServer), nameof(DataTestUtility.IsNotAzureSynapse))] + [InlineData("localhost\\MSSQLSERVER02,1433")] + [InlineData("tcp:localhost\\MSSQLSERVER02,1433")] + [InlineData(" localhost\\MSSQLSERVER02,1433 ")] + [InlineData(" tcp:localhost\\MSSQLSERVER02,1433 ")] + [InlineData(" localhost\\MSSQLSERVER02,1433")] + [InlineData(" tcp:localhost\\MSSQLSERVER02,1433")] + [InlineData("localhost\\MSSQLSERVER02,1433 ")] + [InlineData("tcp:localhost\\MSSQLSERVER02,1433 ")] + public void ParseDataSourceWithInstanceAndPortTestShouldSucceed(string dataSource) + { + DataTestUtility.ParseDataSource(dataSource, out string hostname, out int port, out string instanceName); + Assert.Equal("localhost", hostname); + Assert.Equal("MSSQLSERVER02", instanceName); + Assert.Equal(1433, port); + } + } +} diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/InstanceNameTest/InstanceNameTest.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/InstanceNameTest/InstanceNameTest.cs index 61474ece7f..751cd0a35b 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/InstanceNameTest/InstanceNameTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/InstanceNameTest/InstanceNameTest.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System; +using System.Data.Common; using System.Net; using System.Net.Sockets; using System.Reflection; @@ -87,9 +88,8 @@ public static void ConnectManagedWithInstanceNameTest(bool useMultiSubnetFailove } #if NET6_0_OR_GREATER - [ActiveIssue("27824")] // When specifying instance name and port number, this method call always returns false [ConditionalFact(nameof(IsSPNPortNumberTestForTCP))] - public static void PortNumberInSPNTestForTCP() + public static void SPNTestForTCPMustReturnPortNumber() { string connectionString = DataTestUtility.TCPConnectionString; SqlConnectionStringBuilder builder = new(connectionString); @@ -98,11 +98,23 @@ public static void PortNumberInSPNTestForTCP() Assert.True(port > 0, "Named instance must have a valid port number."); builder.DataSource = $"{builder.DataSource},{port}"; - PortNumberInSPNTest(builder.ConnectionString, port); + PortNumberInSPNTest(connectionString: builder.ConnectionString, expectedPortNumber: port); + } + + [ConditionalFact(nameof(IsSPNPortNumberTestForNP))] + public static void SPNTestForNPMustReturnNamedInstance() + { + string connectionString = DataTestUtility.NPConnectionString; + SqlConnectionStringBuilder builder = new(connectionString); + + DataTestUtility.ParseDataSource(builder.DataSource, out _, out _, out string instanceName); + + Assert.True(!string.IsNullOrEmpty(instanceName), "Instance name must be included in data source."); + PortNumberInSPNTest(connectionString: builder.ConnectionString, expectedInstanceName: instanceName.ToUpper()); } #endif - private static void PortNumberInSPNTest(string connectionString, int expectedPortNumber) + private static void PortNumberInSPNTest(string connectionString, int expectedPortNumber = 0, string expectedInstanceName = null) { if (DataTestUtility.IsIntegratedSecuritySetup()) { @@ -124,20 +136,27 @@ private static void PortNumberInSPNTest(string connectionString, int expectedPor { connection.Open(); - string spnInfo = GetSPNInfo(builder.DataSource); - Assert.Matches(@"MSSQLSvc\/.*:[\d]", spnInfo); - - string[] spnStrs = spnInfo.Split(':'); - int portInSPN = 0; - if (spnStrs.Length > 1) + string spnInfo = GetSPNInfo(builder.DataSource, instanceName); + if (expectedPortNumber > 0) { - int.TryParse(spnStrs[1], out portInSPN); + Assert.Matches(@"MSSQLSvc\/.*:[\d]", spnInfo); + string[] spnStrs = spnInfo.Split(':'); + int portInSPN = 0; + if (spnStrs.Length > 1) + { + int.TryParse(spnStrs[1], out portInSPN); + } + Assert.Equal(expectedPortNumber, portInSPN); + } + else + { + string[] spnStrs = spnInfo.Split(':'); + Assert.Equal(expectedInstanceName, spnStrs[1].ToUpper()); } - Assert.Equal(expectedPortNumber, portInSPN); } } - private static string GetSPNInfo(string dataSource) + private static string GetSPNInfo(string dataSource, string inInstanceName) { Assembly sqlConnectionAssembly = Assembly.GetAssembly(typeof(SqlConnection)); @@ -178,9 +197,12 @@ private static string GetSPNInfo(string dataSource) PropertyInfo serverInfo = dataSrcInfo.GetType().GetProperty("ServerName", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); string serverName = serverInfo.GetValue(dataSrcInfo, null).ToString(); - + // Set the instance name from the data source + PropertyInfo instanceNameToSetInfo = dataSrcInfo.GetType().GetProperty("InstanceName", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); + instanceNameToSetInfo.SetValue(dataSrcInfo, inInstanceName, null); + // Ensure that the instance name is set PropertyInfo instanceNameInfo = dataSrcInfo.GetType().GetProperty("InstanceName", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); - string instanceName = instanceNameInfo.GetValue(dataSrcInfo, null).ToString(); + string instanceName = instanceNameInfo.GetValue(dataSrcInfo, null).ToString().ToUpper(); object port = getPortByInstanceNameInfo.Invoke(ssrpObj, parameters: new object[] { serverName, instanceName, timeoutTimerObj, false, 0 }); @@ -205,6 +227,13 @@ private static bool IsSPNPortNumberTestForTCP() && DataTestUtility.IsNotAzureSynapse()); } + private static bool IsSPNPortNumberTestForNP() + { + return (IsInstanceNameValid(DataTestUtility.NPConnectionString) + && DataTestUtility.IsUsingManagedSNI() + && DataTestUtility.IsNotAzureServer() + && DataTestUtility.IsNotAzureSynapse()); + } private static bool IsInstanceNameValid(string connectionString) { string instanceName = ""; From 8ff48a707ca0db95a18449c108a37e073f04b640 Mon Sep 17 00:00:00 2001 From: Javad Rahnama Date: Fri, 30 Aug 2024 10:39:34 -0700 Subject: [PATCH 06/12] Update README file (#2809) --- README.md | 21 +++++++-------------- 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index 747a542da0..e19c9fb88b 100644 --- a/README.md +++ b/README.md @@ -1,23 +1,17 @@ [![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg?style=flat-square)](https://raw.githubusercontent.com/dotnet/sqlclient/master/LICENSE) [![Nuget](https://img.shields.io/nuget/dt/Microsoft.Data.SqlClient?label=Nuget.org%20Downloads&style=flat-square&color=blue)](https://www.nuget.org/packages/Microsoft.Data.SqlClient) -[![Gitter](https://img.shields.io/gitter/room/badges/shields.svg?style=flat-square&color=blue)](https://gitter.im/Microsoft/mssql-developers) -[![Build status](https://sqlclientdrivers.visualstudio.com/public/_apis/build/status/ADO/CI-SqlClient)](https://sqlclientdrivers.visualstudio.com/public/_build/latest?definitionId=1139) +[![Build status](https://sqlclientdrivers.visualstudio.com/public/_apis/build/status/ADO/CI-SqlClient)](https://sqlclientdrivers.visualstudio.com/public/_build/latest?definitionId=1879) # Microsoft SqlClient Data Provider for SQL Server -Welcome to the home of the Microsoft ADO.NET driver for SQL Server aka the Microsoft.Data.SqlClient GitHub repository. - -Microsoft.Data.SqlClient is a data provider for Microsoft SQL Server and Azure SQL Database. Now in General Availability, it is a union of the two System.Data.SqlClient components which live independently in .NET Framework and .NET Core. Going forward, support for new SQL Server features will be implemented in Microsoft.Data.SqlClient. +Microsoft.Data.SqlClient is a .NET data provider for [Microsoft SQL Server]([url](https://aka.ms/sql)) and the [Azure SQL]([url](https://aka.ms/azure_sql)) family of databases. It grew from a union of the two System.Data.SqlClient components which live independently in .NET Framework and .NET Core. Going forward, support for new SQL Server and Azure SQL features will only be implemented in Microsoft.Data.SqlClient. ## Supportability -The Microsoft.Data.SqlClient package supports the below environments: +The Microsoft.Data.SqlClient package supports the following environments: - .NET Framework 4.6.2+ -- .NET Core 3.1+ -- .NET Standard 2.0+ - -The source code of this library is now available under the MIT license. +- .NET 6.0+ ## Download @@ -25,9 +19,9 @@ The Microsoft.Data.SqlClient NuGet package is available on [NuGet.org](https://w ## SNI Package References -For the .NET Framework driver on Windows, a package reference to [Microsoft.Data.SqlClient.SNI](https://www.nuget.org/packages/Microsoft.Data.SqlClient.SNI/) loads native `Microsoft.Data.SqlClient.SNI.x64.dll` and `Microsoft.Data.SqlClient.SNI.x86.dll` libraries into the client's build directories. +When targeting .NET Framework on Windows, a package reference to [Microsoft.Data.SqlClient.SNI](https://www.nuget.org/packages/Microsoft.Data.SqlClient.SNI/) loads native `Microsoft.Data.SqlClient.SNI..dll` libraries into the client's build directories. -For the .NET Core driver on Windows, a package reference to [Microsoft.Data.SqlClient.SNI.runtime](https://www.nuget.org/packages/Microsoft.Data.SqlClient.SNI.runtime/) loads `arm`, `arm64`, `x64` and `x86` native `Microsoft.Data.SqlClient.SNI.dll` libraries into the client's build directories. +When targeting .NET on Windows, a package reference to [Microsoft.Data.SqlClient.SNI.runtime](https://www.nuget.org/packages/Microsoft.Data.SqlClient.SNI.runtime/) loads `arm64`, `x64` and `x86` native `Microsoft.Data.SqlClient.SNI.dll` libraries into subdirectories in the client's build directory. ## Helpful Links @@ -40,7 +34,6 @@ For the .NET Core driver on Windows, a package reference to [Microsoft.Data.SqlC | Support Policy | [SUPPORT.md](SUPPORT.md) | | Code of Conduct | [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md) | | Copyright Information | [COPYRIGHT.md](COPYRIGHT.md) | -| | | ## Our Featured Contributors @@ -65,7 +58,7 @@ All preview and stable driver release notes are available under [release-notes]( ## Porting from System.Data.SqlClient -Refer to [porting-cheat-sheet.md](porting-cheat-sheet.md) for a safe porting experience from System.Data.SqlClient to Microsoft.Data.SqlClient and share your experience with us by advancing this guide for future developers. +Refer to [porting-cheat-sheet.md](porting-cheat-sheet.md) for a safe porting experience from System.Data.SqlClient to Microsoft.Data.SqlClient and share your experience with us by enhancing this guide for future developers. ## Still have questions? From d89372af4153ec41f320b912748e032b160160c9 Mon Sep 17 00:00:00 2001 From: Deepak Saini Date: Sat, 31 Aug 2024 04:04:13 +0530 Subject: [PATCH 07/12] Add Feature Extension for Json Support (#2773) * Add Feature Extension for Json Support (#2696) * change json hexa code and fix invalid login error * Change name to match other naming conventions * process JSONSUpport acknowledgement * Fix naming conventions * Processing 2nd byte from server * Changes for netfx * Json support feature ack in Test TDS server * Remove enabled flag * address PR comments * Enable JSON only in debug bits * Enable json tests in debug mode only * resolve PR comments --------- Co-authored-by: saurabh500 <1623701+saurabh500@users.noreply.github.com> --- .../SqlClient/SqlInternalConnectionTds.cs | 25 ++++++++++++- .../src/Microsoft/Data/SqlClient/TdsParser.cs | 23 ++++++++++++ .../SqlClient/SqlInternalConnectionTds.cs | 25 +++++++++++++ .../src/Microsoft/Data/SqlClient/TdsParser.cs | 23 ++++++++++++ .../src/Microsoft/Data/SqlClient/TdsEnums.cs | 7 +++- .../TDS/TDS.EndPoint/ITDSServerSession.cs | 5 +++ .../tools/TDS/TDS.Servers/GenericTDSServer.cs | 36 +++++++++++++++++++ .../TDS.Servers/GenericTDSServerSession.cs | 5 +++ .../tests/tools/TDS/TDS/TDSFeatureID.cs | 5 +++ 9 files changed, 152 insertions(+), 2 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlInternalConnectionTds.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlInternalConnectionTds.cs index f4df2b11f9..d976bb06fc 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlInternalConnectionTds.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlInternalConnectionTds.cs @@ -200,6 +200,9 @@ internal bool IsDNSCachingBeforeRedirectSupported internal SQLDNSInfo pendingSQLDNSObject = null; + // Json Support Flag + internal bool IsJsonSupportEnabled = false; + // TCE flags internal byte _tceVersionSupported; @@ -1362,7 +1365,9 @@ private void Login(ServerInfo server, TimeoutTimer timeout, string newPassword, // The SQLDNSCaching feature is implicitly set requestedFeatures |= TdsEnums.FeatureExtension.SQLDNSCaching; - +#if DEBUG + requestedFeatures |= TdsEnums.FeatureExtension.JsonSupport; +#endif _parser.TdsLogin(login, requestedFeatures, _recoverySessionData, _fedAuthFeatureExtensionData, encrypt); } @@ -2811,6 +2816,24 @@ internal void OnFeatureExtAck(int featureId, byte[] data) break; } + case TdsEnums.FEATUREEXT_JSONSUPPORT: + { + SqlClientEventSource.Log.TryAdvancedTraceEvent(" {0}, Received feature extension acknowledgement for JSONSUPPORT", ObjectID); + if (data.Length != 1) + { + SqlClientEventSource.Log.TryTraceEvent(" {0}, Unknown token for JSONSUPPORT", ObjectID); + throw SQL.ParsingError(ParsingErrorState.CorruptedTdsStream); + } + byte jsonSupportVersion = data[0]; + if (jsonSupportVersion == 0 || jsonSupportVersion > TdsEnums.MAX_SUPPORTED_JSON_VERSION) + { + SqlClientEventSource.Log.TryTraceEvent(" {0}, Invalid version number for JSONSUPPORT", ObjectID); + throw SQL.ParsingError(); + } + IsJsonSupportEnabled = true; + break; + } + default: { // Unknown feature ack diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs index 4cee4ff95c..edeecb6c9f 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs @@ -8411,6 +8411,24 @@ internal int WriteFedAuthFeatureRequest(FederatedAuthenticationFeatureExtensionD return len; } + internal int WriteJsonSupportFeatureRequest(bool write /* if false just calculates the length */) + { + int len = 6; // 1byte = featureID, 4bytes = featureData length, 1 bytes = Version + + if (write) + { + // Write Feature ID + _physicalStateObj.WriteByte(TdsEnums.FEATUREEXT_JSONSUPPORT); + + // Feature Data Length + WriteInt(1, _physicalStateObj); + + _physicalStateObj.WriteByte(TdsEnums.MAX_SUPPORTED_JSON_VERSION); + } + + return len; + } + private void WriteLoginData(SqlLogin rec, TdsEnums.FeatureExtension requestedFeatures, SessionData recoverySessionData, @@ -8723,6 +8741,11 @@ private int ApplyFeatureExData(TdsEnums.FeatureExtension requestedFeatures, length += WriteSQLDNSCachingFeatureRequest(write); } + if ((requestedFeatures & TdsEnums.FeatureExtension.JsonSupport) != 0) + { + length += WriteJsonSupportFeatureRequest(write); + } + length++; // for terminator if (write) { diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlInternalConnectionTds.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlInternalConnectionTds.cs index 0aaa4a6d93..cdb7ba2173 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlInternalConnectionTds.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlInternalConnectionTds.cs @@ -212,6 +212,9 @@ internal bool IsDNSCachingBeforeRedirectSupported internal SQLDNSInfo pendingSQLDNSObject = null; + // Json Support Flag + internal bool IsJsonSupportEnabled = false; + // TCE flags internal byte _tceVersionSupported; @@ -1638,6 +1641,10 @@ private void Login(ServerInfo server, TimeoutTimer timeout, string newPassword, // The SQLDNSCaching feature is implicitly set requestedFeatures |= TdsEnums.FeatureExtension.SQLDNSCaching; +#if DEBUG + requestedFeatures |= TdsEnums.FeatureExtension.JsonSupport; +#endif + _parser.TdsLogin(login, requestedFeatures, _recoverySessionData, _fedAuthFeatureExtensionData, _originalNetworkAddressInfo, encrypt); } @@ -3239,6 +3246,24 @@ internal void OnFeatureExtAck(int featureId, byte[] data) break; } + case TdsEnums.FEATUREEXT_JSONSUPPORT: + { + SqlClientEventSource.Log.TryAdvancedTraceEvent(" {0}, Received feature extension acknowledgement for JSONSUPPORT", ObjectID); + if (data.Length != 1) + { + SqlClientEventSource.Log.TryTraceEvent(" {0}, Unknown token for JSONSUPPORT", ObjectID); + throw SQL.ParsingError(ParsingErrorState.CorruptedTdsStream); + } + byte jsonSupportVersion = data[0]; + if (jsonSupportVersion == 0 || jsonSupportVersion > TdsEnums.MAX_SUPPORTED_JSON_VERSION) + { + SqlClientEventSource.Log.TryTraceEvent(" {0}, Invalid version number for JSONSUPPORT", ObjectID); + throw SQL.ParsingError(ParsingErrorState.CorruptedTdsStream); + } + IsJsonSupportEnabled = true; + break; + } + default: { // Unknown feature ack diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.cs index fb0884bb36..f9b1306e42 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.cs @@ -9252,6 +9252,24 @@ internal int WriteFedAuthFeatureRequest(FederatedAuthenticationFeatureExtensionD return len; } + internal int WriteJsonSupportFeatureRequest(bool write /* if false just calculates the length */) + { + int len = 6; // 1byte = featureID, 4bytes = featureData length, 1 bytes = Version + + if (write) + { + // Write Feature ID + _physicalStateObj.WriteByte(TdsEnums.FEATUREEXT_JSONSUPPORT); + + // Feature Data Length + WriteInt(1, _physicalStateObj); + + _physicalStateObj.WriteByte(TdsEnums.MAX_SUPPORTED_JSON_VERSION); + } + + return len; + } + private void WriteLoginData(SqlLogin rec, TdsEnums.FeatureExtension requestedFeatures, SessionData recoverySessionData, @@ -9581,6 +9599,11 @@ private int ApplyFeatureExData(TdsEnums.FeatureExtension requestedFeatures, length += WriteSQLDNSCachingFeatureRequest(write); } + if ((requestedFeatures & TdsEnums.FeatureExtension.JsonSupport) != 0) + { + length += WriteJsonSupportFeatureRequest(write); + } + length++; // for terminator if (write) { diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/TdsEnums.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/TdsEnums.cs index 8c7119a695..685002790c 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/TdsEnums.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/TdsEnums.cs @@ -238,6 +238,7 @@ public enum EnvChangeType : byte public const byte FEATUREEXT_DATACLASSIFICATION = 0x09; public const byte FEATUREEXT_UTF8SUPPORT = 0x0A; public const byte FEATUREEXT_SQLDNSCACHING = 0x0B; + public const byte FEATUREEXT_JSONSUPPORT = 0x0D; [Flags] public enum FeatureExtension : uint @@ -250,7 +251,8 @@ public enum FeatureExtension : uint AzureSQLSupport = 1 << (TdsEnums.FEATUREEXT_AZURESQLSUPPORT - 1), DataClassification = 1 << (TdsEnums.FEATUREEXT_DATACLASSIFICATION - 1), UTF8Support = 1 << (TdsEnums.FEATUREEXT_UTF8SUPPORT - 1), - SQLDNSCaching = 1 << (TdsEnums.FEATUREEXT_SQLDNSCACHING - 1) + SQLDNSCaching = 1 << (TdsEnums.FEATUREEXT_SQLDNSCACHING - 1), + JsonSupport = 1 << (TdsEnums.FEATUREEXT_JSONSUPPORT - 1) } public const uint UTF8_IN_TDSCOLLATION = 0x4000000; @@ -994,6 +996,9 @@ internal enum FedAuthInfoId : byte internal const byte DATA_CLASSIFICATION_VERSION_WITHOUT_RANK_SUPPORT = 0x01; internal const byte DATA_CLASSIFICATION_VERSION_MAX_SUPPORTED = 0x02; + // JSON Support constants + internal const byte MAX_SUPPORTED_JSON_VERSION = 0x01; + // TCE Related constants internal const byte MAX_SUPPORTED_TCE_VERSION = 0x03; // max version internal const byte MIN_TCE_VERSION_WITH_ENCLAVE_SUPPORT = 0x02; // min version with enclave support diff --git a/src/Microsoft.Data.SqlClient/tests/tools/TDS/TDS.EndPoint/ITDSServerSession.cs b/src/Microsoft.Data.SqlClient/tests/tools/TDS/TDS.EndPoint/ITDSServerSession.cs index 0c9320f512..bbe039d426 100644 --- a/src/Microsoft.Data.SqlClient/tests/tools/TDS/TDS.EndPoint/ITDSServerSession.cs +++ b/src/Microsoft.Data.SqlClient/tests/tools/TDS/TDS.EndPoint/ITDSServerSession.cs @@ -77,5 +77,10 @@ public interface ITDSServerSession /// Indicates whether this session supports transport-level recovery /// bool IsSessionRecoveryEnabled { get; set; } + + /// + /// Indicates whether the client supports Json column type + /// + bool IsJsonSupportEnabled { get; set; } } } diff --git a/src/Microsoft.Data.SqlClient/tests/tools/TDS/TDS.Servers/GenericTDSServer.cs b/src/Microsoft.Data.SqlClient/tests/tools/TDS/TDS.Servers/GenericTDSServer.cs index 535304964d..e0c243dcc8 100644 --- a/src/Microsoft.Data.SqlClient/tests/tools/TDS/TDS.Servers/GenericTDSServer.cs +++ b/src/Microsoft.Data.SqlClient/tests/tools/TDS/TDS.Servers/GenericTDSServer.cs @@ -232,6 +232,14 @@ public virtual TDSMessageCollection OnLogin7Request(ITDSServerSession session, T break; } +#if DEBUG + case TDSFeatureID.JsonSupport: + { + // Enable Json Support + session.IsJsonSupportEnabled = true; + break; + } +#endif default: { // Do nothing @@ -544,6 +552,34 @@ protected virtual TDSMessageCollection OnAuthenticationCompleted(ITDSServerSessi responseMessage.Add(featureExtActToken); } +#if DEBUG + // Check if Json is supported + if (session.IsJsonSupportEnabled) + { + // Create ack data (1 byte: Version number) + byte[] data = new byte[1]; + data[0] = (byte)1; + + // Create Json support as a generic feature extension option + TDSFeatureExtAckGenericOption jsonSupportOption = new TDSFeatureExtAckGenericOption(TDSFeatureID.JsonSupport, (uint)data.Length, data); + + // Look for feature extension token + TDSFeatureExtAckToken featureExtAckToken = (TDSFeatureExtAckToken)responseMessage.Where(t => t is TDSFeatureExtAckToken).FirstOrDefault(); + + if (featureExtAckToken == null) + { + // Create feature extension ack token + featureExtAckToken = new TDSFeatureExtAckToken(jsonSupportOption); + responseMessage.Add(featureExtAckToken); + } + else + { + // Update the existing token + featureExtAckToken.Options.Add(jsonSupportOption); + } + } +#endif + // Create DONE token TDSDoneToken doneToken = new TDSDoneToken(TDSDoneTokenStatusType.Final); diff --git a/src/Microsoft.Data.SqlClient/tests/tools/TDS/TDS.Servers/GenericTDSServerSession.cs b/src/Microsoft.Data.SqlClient/tests/tools/TDS/TDS.Servers/GenericTDSServerSession.cs index 4c1de9f986..3272036e15 100644 --- a/src/Microsoft.Data.SqlClient/tests/tools/TDS/TDS.Servers/GenericTDSServerSession.cs +++ b/src/Microsoft.Data.SqlClient/tests/tools/TDS/TDS.Servers/GenericTDSServerSession.cs @@ -108,6 +108,11 @@ public class GenericTDSServerSession : ITDSServerSession /// public bool IsSessionRecoveryEnabled { get; set; } + /// + /// Indicates whether this session supports Json column type + /// + public bool IsJsonSupportEnabled { get; set; } + #region Session Options /// diff --git a/src/Microsoft.Data.SqlClient/tests/tools/TDS/TDS/TDSFeatureID.cs b/src/Microsoft.Data.SqlClient/tests/tools/TDS/TDS/TDSFeatureID.cs index bac86b591c..eb84a631d0 100644 --- a/src/Microsoft.Data.SqlClient/tests/tools/TDS/TDS/TDSFeatureID.cs +++ b/src/Microsoft.Data.SqlClient/tests/tools/TDS/TDS/TDSFeatureID.cs @@ -19,6 +19,11 @@ public enum TDSFeatureID : byte /// FederatedAuthentication = 0x02, + /// + /// JSON Support + /// + JsonSupport = 0x0D, + /// /// End of the list /// From b6a28f7f9b65a36af41533a44b4d4fb7bf0c1c65 Mon Sep 17 00:00:00 2001 From: Benjamin Russell Date: Thu, 5 Sep 2024 10:56:20 -0500 Subject: [PATCH 08/12] XML Documentation Fix - Batch 1 (#2822) * Batch 1 of fixing xml files * Removing CDATA blocks, fixing cref links * Fixing a couple more issues --- ...DAuthenticationCustomDeviceFlowCallback.cs | 30 - ...tionClientIdAzureAuthenticationProvider.cs | 26 - ...viceCodeFlowAzureAuthenticationProvider.cs | 57 -- .../ActiveDirectoryAuthenticationProvider.xml | 209 ++++--- .../ApplicationIntent.xml | 41 +- .../OnChangeEventHandler.xml | 31 +- .../PoolBlockingPeriod.xml | 36 +- .../Microsoft.Data.SqlClient/SortOrder.xml | 45 +- .../SqlAuthenticationInitializer.xml | 31 +- .../SqlAuthenticationMethod.xml | 100 ++-- .../SqlAuthenticationParameters.xml | 112 ++-- .../SqlAuthenticationProvider.xml | 99 +++- .../SqlAuthenticationToken.xml | 44 +- .../Microsoft.Data.SqlClient/SqlBatch.xml | 524 ++++++++++++------ 14 files changed, 783 insertions(+), 602 deletions(-) delete mode 100644 doc/samples/AADAuthenticationCustomDeviceFlowCallback.cs delete mode 100644 doc/samples/ApplicationClientIdAzureAuthenticationProvider.cs delete mode 100644 doc/samples/CustomDeviceCodeFlowAzureAuthenticationProvider.cs diff --git a/doc/samples/AADAuthenticationCustomDeviceFlowCallback.cs b/doc/samples/AADAuthenticationCustomDeviceFlowCallback.cs deleted file mode 100644 index bda3554bbe..0000000000 --- a/doc/samples/AADAuthenticationCustomDeviceFlowCallback.cs +++ /dev/null @@ -1,30 +0,0 @@ -// -using System; -using System.Threading.Tasks; -using Microsoft.Identity.Client; -using Microsoft.Data.SqlClient; - -namespace CustomAuthenticationProviderExamples -{ - public class Program - { - public static void Main() - { - SqlAuthenticationProvider authProvider = new ActiveDirectoryAuthenticationProvider(CustomDeviceFlowCallback); - SqlAuthenticationProvider.SetProvider(SqlAuthenticationMethod.ActiveDirectoryDeviceCodeFlow, authProvider); - using (SqlConnection sqlConnection = new SqlConnection("Server=.database.windows.net;Authentication=Active Directory Device Code Flow;Database=;")) - { - sqlConnection.Open(); - Console.WriteLine("Connected successfully!"); - } - } - - private static Task CustomDeviceFlowCallback(DeviceCodeResult result) - { - // Provide custom logic to process result information and read device code. - Console.WriteLine(result.Message); - return Task.FromResult(0); - } - } -} -// diff --git a/doc/samples/ApplicationClientIdAzureAuthenticationProvider.cs b/doc/samples/ApplicationClientIdAzureAuthenticationProvider.cs deleted file mode 100644 index f206a1c29e..0000000000 --- a/doc/samples/ApplicationClientIdAzureAuthenticationProvider.cs +++ /dev/null @@ -1,26 +0,0 @@ -// -using System; -using Microsoft.Data.SqlClient; - -namespace CustomAuthenticationProviderExamples -{ - public class Program - { - public static void Main() - { - // Supported for all authentication modes supported by ActiveDirectoryAuthenticationProvider - ActiveDirectoryAuthenticationProvider provider = new ActiveDirectoryAuthenticationProvider(""); - if (provider.IsSupported(SqlAuthenticationMethod.ActiveDirectoryInteractive)) - { - SqlAuthenticationProvider.SetProvider(SqlAuthenticationMethod.ActiveDirectoryInteractive, provider); - } - - using (SqlConnection sqlConnection = new SqlConnection("Server=.database.windows.net;Authentication=Active Directory Interactive;Database=;")) - { - sqlConnection.Open(); - Console.WriteLine("Connected successfully!"); - } - } - } -} -// diff --git a/doc/samples/CustomDeviceCodeFlowAzureAuthenticationProvider.cs b/doc/samples/CustomDeviceCodeFlowAzureAuthenticationProvider.cs deleted file mode 100644 index 68d792fef5..0000000000 --- a/doc/samples/CustomDeviceCodeFlowAzureAuthenticationProvider.cs +++ /dev/null @@ -1,57 +0,0 @@ -// -using System; -using System.Threading.Tasks; -using Microsoft.Identity.Client; -using Microsoft.Data.SqlClient; - -namespace CustomAuthenticationProviderExamples -{ - /// - /// Example demonstrating creating a custom device code flow authentication provider and attaching it to the driver. - /// This is helpful for applications that wish to override the Callback for the Device Code Result implemented by the SqlClient driver. - /// - public class CustomDeviceCodeFlowAzureAuthenticationProvider : SqlAuthenticationProvider - { - public override async Task AcquireTokenAsync(SqlAuthenticationParameters parameters) - { - string clientId = "my-client-id"; - string clientName = "My Application Name"; - string s_defaultScopeSuffix = "/.default"; - - string[] scopes = new string[] { parameters.Resource.EndsWith(s_defaultScopeSuffix) ? parameters.Resource : parameters.Resource + s_defaultScopeSuffix }; - - IPublicClientApplication app = PublicClientApplicationBuilder.Create(clientId) - .WithAuthority(parameters.Authority) - .WithClientName(clientName) - .WithRedirectUri("https://login.microsoftonline.com/common/oauth2/nativeclient") - .Build(); - - AuthenticationResult result = await app.AcquireTokenWithDeviceCode(scopes, - deviceCodeResult => CustomDeviceFlowCallback(deviceCodeResult)).ExecuteAsync(); - return new SqlAuthenticationToken(result.AccessToken, result.ExpiresOn); - } - - public override bool IsSupported(SqlAuthenticationMethod authenticationMethod) => authenticationMethod.Equals(SqlAuthenticationMethod.ActiveDirectoryDeviceCodeFlow); - - private Task CustomDeviceFlowCallback(DeviceCodeResult result) - { - Console.WriteLine(result.Message); - return Task.FromResult(0); - } - } - - public class Program - { - public static void Main() - { - // Register our custom authentication provider class to override Active Directory Device Code Flow - SqlAuthenticationProvider.SetProvider(SqlAuthenticationMethod.ActiveDirectoryDeviceCodeFlow, new CustomDeviceCodeFlowAzureAuthenticationProvider()); - using (SqlConnection sqlConnection = new SqlConnection("Server=.database.windows.net;Authentication=Active Directory Device Code Flow;Database=;")) - { - sqlConnection.Open(); - Console.WriteLine("Connected successfully!"); - } - } - } -} -// diff --git a/doc/snippets/Microsoft.Data.SqlClient/ActiveDirectoryAuthenticationProvider.xml b/doc/snippets/Microsoft.Data.SqlClient/ActiveDirectoryAuthenticationProvider.xml index 5a69be7478..a6444f700a 100644 --- a/doc/snippets/Microsoft.Data.SqlClient/ActiveDirectoryAuthenticationProvider.xml +++ b/doc/snippets/Microsoft.Data.SqlClient/ActiveDirectoryAuthenticationProvider.xml @@ -2,7 +2,7 @@ - This class implements and is used for active directory federated authentication mechanisms. + This class implements and is used for active directory federated authentication mechanisms. @@ -11,78 +11,165 @@ - Client Application Id to be used for acquiring an access token for federated authentication. The driver uses its own application client id by default. + + Client Application Id to be used for acquiring an access token for federated authentication. The driver uses its own application client id by default. + Initializes the class with the provided application client id. - - - + The following example demonstrates providing a user-defined application client id to SqlClient for the "Active Directory Interactive" authentication method: + + using System; + using Microsoft.Data.SqlClient; -## Examples - The following example demonstrates providing a user-defined application client id to SqlClient for the "Active Directory Interactive" authentication method: - - [!code-csharp[ActiveDirectory_ApplicationClientId Example#1](~/../sqlclient/doc/samples/ApplicationClientIdAzureAuthenticationProvider.cs#1)] - - ]]> - - + namespace CustomAuthenticationProviderExamples + { + public class Program + { + public static void Main() + { + // Supported for all authentication modes supported by ActiveDirectoryAuthenticationProvider + ActiveDirectoryAuthenticationProvider provider = new ActiveDirectoryAuthenticationProvider("<application_client_id>"); + if (provider.IsSupported(SqlAuthenticationMethod.ActiveDirectoryInteractive)) + { + SqlAuthenticationProvider.SetProvider(SqlAuthenticationMethod.ActiveDirectoryInteractive, provider); + } + + using (SqlConnection sqlConnection = new SqlConnection("Server=<myserver>.database.windows.net;Authentication=Active Directory Interactive;Database=>db<;")) + { + sqlConnection.Open(); + Console.WriteLine("Connected successfully!"); + } + } + } + } + + - The callback method to be used with 'Active Directory Device Code Flow' authentication. - (Optional) Client Application Id to be used for acquiring an access token for federated authentication. The driver uses its own application client id by default. + + The callback method to be used with 'Active Directory Device Code Flow' authentication. + + + (Optional) Client Application Id to be used for acquiring an access token for federated authentication. The driver uses its own application client id by default. + Initializes the class with the provided device code flow callback method and application client id. - The Active Directory authentication parameters passed to authentication providers. - Acquires a security token from the authority. - Represents an asynchronous operation that returns the authentication token. + + The Active Directory authentication parameters passed to authentication providers. + + + Acquires a security token from the authority. + + + Represents an asynchronous operation that returns the authentication token. + - Clears cached user tokens from the token provider. - This will cause interactive authentication prompts to appear again if tokens were previously being obtained from the cache. + + Clears cached user tokens from the token provider. + + + This will cause interactive authentication prompts to appear again if tokens were previously being obtained from the cache. + - The callback method to be used with 'Active Directory Device Code Flow' authentication. - Sets the callback method, overriding the default implementation that processes the result for 'Active Directory Device Code Flow' authentication. - - - + The callback method to be used with 'Active Directory Device Code Flow' authentication. + + + Sets the callback method, overriding the default implementation that processes the result for 'Active Directory Device Code Flow' authentication. + + + The following example demonstrates providing a custom device flow callback to SqlClient for the Device Code Flow authentication method: + + using System; + using System.Threading.Tasks; + using Microsoft.Identity.Client; + using Microsoft.Data.SqlClient; -[!code-csharp[ActiveDirectory_DeviceCodeFlowCallback Example#1](~/../sqlclient/doc/samples/AADAuthenticationCustomDeviceFlowCallback.cs#1)] - -]]> - - + namespace CustomAuthenticationProviderExamples + { + public class Program + { + public static void Main() + { + SqlAuthenticationProvider authProvider = new ActiveDirectoryAuthenticationProvider(CustomDeviceFlowCallback); + SqlAuthenticationProvider.SetProvider(SqlAuthenticationMethod.ActiveDirectoryDeviceCodeFlow, authProvider); + using (SqlConnection sqlConnection = new SqlConnection("Server=<myserver>.database.windows.net;Authentication=Active Directory Device Code Flow;Database=<db>;")) + { + sqlConnection.Open(); + Console.WriteLine("Connected successfully!"); + } + } + + private static Task CustomDeviceFlowCallback(DeviceCodeResult result) + { + // Provide custom logic to process result information and read device code. + Console.WriteLine(result.Message); + return Task.FromResult(0); + } + } + } + + + - The parent as an object, in order to be used from shared .NET Standard assemblies. - Sets a reference to the ViewController (if using Xamarin.iOS), Activity (if using Xamarin.Android) IWin32Window or IntPtr (if using .NET Framework). Used for invoking the browser for Active Directory Interactive authentication. - Mandatory to be set only on Android. See https://aka.ms/msal-net-android-activity for further documentation and details. + + The parent as an object, in order to be used from shared .NET Standard assemblies. + + + Sets a reference to the ViewController (if using Xamarin.iOS), Activity (if using Xamarin.Android) IWin32Window or IntPtr (if using .NET Framework). Used for invoking the browser for Active Directory Interactive authentication. + + + Mandatory to be set only on Android. See https://aka.ms/msal-net-android-activity for further documentation and details. + - A function to return the current window. - Sets a reference to the current that triggers the browser to be shown. Used to center the browser pop-up onto this window." + + A function to return the current window. + + + Sets a reference to the current that triggers the browser to be shown. Used to center the browser pop-up onto this window." + - The callback method to be called by MSAL.NET to delegate the Web user interface with the Secure Token Service (STS). - Sets a callback method which is invoked with a custom Web UI instance that will let the user sign-in with Azure Active Directory, present consent if needed, and get back the authorization code. Applicable when working with Active Directory Interactive authentication. - The "authorizationUri" is crafted to leverage PKCE in order to protect the token from a man in the middle attack. Only MSAL.NET can redeem the code. In the event of cancellation, the implementer should return . + + The callback method to be called by MSAL.NET to delegate the Web user interface with the Secure Token Service (STS). + + + Sets a callback method which is invoked with a custom Web UI instance that will let the user sign-in with Azure Active Directory, present consent if needed, and get back the authorization code. Applicable when working with Active Directory Interactive authentication. + + + The "authorizationUri" is crafted to leverage PKCE in order to protect the token from a man in the middle attack. Only MSAL.NET can redeem the code. In the event of cancellation, the implementer should return . + - The authentication method. - This method is called immediately before the provider is added to authentication provider registry. - Avoid performing long-waiting tasks in this method, since it can block other threads from accessing the provider registry. + + The authentication method. + + + This method is called immediately before the provider is added to authentication provider registry. + + + Avoid performing long-waiting tasks in this method, since it can block other threads from accessing the provider registry. + - The authentication method. - This method is called immediately before the provider is removed from the authentication provider registry. - For example, this method is called when a different provider with the same authentication method overrides this provider in the authentication provider registry. Avoid performing long-waiting task in this method, since it can block other threads from accessing the provider registry. + + The authentication method. + + + This method is called immediately before the provider is removed from the authentication provider registry. + + + For example, this method is called when a different provider with the same authentication method overrides this provider in the authentication provider registry. Avoid performing long-waiting task in this method, since it can block other threads from accessing the provider registry. + The authentication method. @@ -91,23 +178,17 @@ The following example demonstrates providing a custom device flow callback to Sq if the specified authentication method is supported; otherwise, . - - are: - -- Active Directory Password -- Active Directory Integrated -- Active Directory Interactive -- Active Directory Service Principal -- Active Directory Device Code Flow -- Active Directory Managed Identity -- Active Directory MSI -- Active Directory Default - - ]]> - + The supported authentication modes with are: + + Active Directory Password + Active Directory Integrated + Active Directory Interactive + Active Directory Service Principal + Active Directory Device Code Flow + Active Directory Managed Identity + Active Directory MSI + Active Directory Default + diff --git a/doc/snippets/Microsoft.Data.SqlClient/ApplicationIntent.xml b/doc/snippets/Microsoft.Data.SqlClient/ApplicationIntent.xml index e4c32bb13d..621c3461c3 100644 --- a/doc/snippets/Microsoft.Data.SqlClient/ApplicationIntent.xml +++ b/doc/snippets/Microsoft.Data.SqlClient/ApplicationIntent.xml @@ -1,20 +1,23 @@ - - - - - Specifies a value for . Possible values are and . - - To be added. - - - The application workload type when connecting to a server is read write. - 0 - 0 - - - The application workload type when connecting to a server is read only. - 1 - 1 - - + + + + + Specifies a value for . Possible values are and . + + + + + The application workload type when connecting to a server is read write. + + 0 + 0 + + + + The application workload type when connecting to a server is read only. + + 1 + 1 + + diff --git a/doc/snippets/Microsoft.Data.SqlClient/OnChangeEventHandler.xml b/doc/snippets/Microsoft.Data.SqlClient/OnChangeEventHandler.xml index 57c5fbf909..1ec1ff2ee3 100644 --- a/doc/snippets/Microsoft.Data.SqlClient/OnChangeEventHandler.xml +++ b/doc/snippets/Microsoft.Data.SqlClient/OnChangeEventHandler.xml @@ -1,17 +1,16 @@ - - - - The source of the event. - A object that contains the event data. - Handles the event that is fired when a notification is received for any of the commands associated with a object. - - event does not necessarily imply a change in the data. Other circumstances, such as time-out expired and failure to set the notification request, also generate . - -]]> - - - + + + + The source of the event. + + A object that contains the event data. + + + Handles the event that is fired when a notification is received for any of the commands associated with a object. + + + The event does not necessarily imply a change in the data. Other circumstances, such as time-out expired and failure to set the notification request, also generate . + + + diff --git a/doc/snippets/Microsoft.Data.SqlClient/PoolBlockingPeriod.xml b/doc/snippets/Microsoft.Data.SqlClient/PoolBlockingPeriod.xml index 43f4046304..5f791173bc 100644 --- a/doc/snippets/Microsoft.Data.SqlClient/PoolBlockingPeriod.xml +++ b/doc/snippets/Microsoft.Data.SqlClient/PoolBlockingPeriod.xml @@ -1,20 +1,20 @@ - - - Specifies a value for the property. - To be added. - - - Blocking period OFF for Azure SQL servers, but ON for all other SQL servers. - 0 - - - Blocking period ON for all SQL servers including Azure SQL servers. - 1 - - - Blocking period OFF for Azure SQL servers, but ON for all other SQL servers. - 2 - - + + + Specifies a value for the property. + To be added. + + + Blocking period OFF for Azure SQL servers, but ON for all other SQL servers. + 0 + + + Blocking period ON for all SQL servers including Azure SQL servers. + 1 + + + Blocking period OFF for Azure SQL servers, but ON for all other SQL servers. + 2 + + diff --git a/doc/snippets/Microsoft.Data.SqlClient/SortOrder.xml b/doc/snippets/Microsoft.Data.SqlClient/SortOrder.xml index 7a6def3284..d28534a83f 100644 --- a/doc/snippets/Microsoft.Data.SqlClient/SortOrder.xml +++ b/doc/snippets/Microsoft.Data.SqlClient/SortOrder.xml @@ -1,25 +1,22 @@ - - - - - Specifies how rows of data are sorted. - - To be added. - - - The default. No sort order is specified. - -1 - -1 - - - Rows are sorted in ascending order. - 0 - 0 - - - Rows are sorted in descending order. - 1 - 1 - - + + + + Specifies how rows of data are sorted. + + + The default. No sort order is specified. + -1 + -1 + + + Rows are sorted in ascending order. + 0 + 0 + + + Rows are sorted in descending order. + 1 + 1 + + diff --git a/doc/snippets/Microsoft.Data.SqlClient/SqlAuthenticationInitializer.xml b/doc/snippets/Microsoft.Data.SqlClient/SqlAuthenticationInitializer.xml index 41a3734d3d..b2ae7afbf2 100644 --- a/doc/snippets/Microsoft.Data.SqlClient/SqlAuthenticationInitializer.xml +++ b/doc/snippets/Microsoft.Data.SqlClient/SqlAuthenticationInitializer.xml @@ -1,14 +1,19 @@ - - - - Called from constructors in derived classes to initialize the class. - To be added. - - - Default Constructor to initialize the class. - - - When overridden in a derived class, initializes the authentication initializer. This method is called by the constructor during startup. - - + + + + + Called from constructors in derived classes to initialize the class. + + + + + Default Constructor to initialize the class. + + + + + When overridden in a derived class, initializes the authentication initializer. This method is called by the constructor during startup. + + + diff --git a/doc/snippets/Microsoft.Data.SqlClient/SqlAuthenticationMethod.xml b/doc/snippets/Microsoft.Data.SqlClient/SqlAuthenticationMethod.xml index d179ce1196..70b6c2e821 100644 --- a/doc/snippets/Microsoft.Data.SqlClient/SqlAuthenticationMethod.xml +++ b/doc/snippets/Microsoft.Data.SqlClient/SqlAuthenticationMethod.xml @@ -1,53 +1,51 @@ - - - Describes the different SQL authentication methods that can be used by a client connecting to Azure SQL Database. For details, see Connecting to SQL Database By Using Azure Active Directory Authentication. - - To be added. - - - The authentication method is not specified. - 0 - - - The authentication method is Sql Password. - 1 - - - The authentication method uses Active Directory Password. Use Active Directory Password to connect to a SQL Database using an Azure AD principal name and password. - 2 - - - The authentication method uses Active Directory Integrated. Use Active Directory Integrated to connect to a SQL Database using integrated Windows authentication. - 3 - - - The authentication method uses Active Directory Interactive. Use Active Directory Interactive to connect to a SQL Database with an interactive authentication flow. - 4 - - - The authentication method uses Active Directory Service Principal. Use Active Directory Service Principal to connect to a SQL Database using the client ID and secret of a service principal identity. - 5 - - - The authentication method uses Active Directory Device Code Flow. Use Active Directory Device Code Flow to connect to a SQL Database from devices and operating systems that do not provide a Web browser, using another device to perform interactive authentication. - 6 - - - The authentication method uses Active Directory Managed Identity. Use System Assigned or User Assigned Managed Identity to connect to SQL Database from Azure client environments that have enabled support for Managed Identity. For User Assigned Managed Identity, 'User Id' or 'UID' is required to be set to the "client ID" of the user identity. - 7 - - - Alias for "Active Directory Managed Identity" authentication method. Use System Assigned or User Assigned Managed Identity to connect to SQL Database from Azure client environments that have enabled support for Managed Identity. For User Assigned Managed Identity, 'User Id' or 'UID' is required to be set to the "client ID" of the user identity. - 8 - - - The authentication method uses Active Directory Default. Use this mode to connect to a SQL Database using multiple non-interactive authentication methods tried sequentially to acquire an access token. This method does not fallback to the "Active Directory Interactive" authentication method. - 9 - - - The authentication method uses Active Directory Workload Identity. Use a federated User Assigned Managed Identity to connect to SQL Database from Azure client environments that have enabled support for Workload Identity. The 'User Id' or 'UID' is required to be set to the "client ID" of the user identity. - 10 - - + + + Describes the different SQL authentication methods that can be used by a client connecting to Azure SQL Database. For details, see Connecting to SQL Database By Using Azure Active Directory Authentication. + + + The authentication method is not specified. + 0 + + + The authentication method is Sql Password. + 1 + + + The authentication method uses Active Directory Password. Use Active Directory Password to connect to a SQL Database using an Azure AD principal name and password. + 2 + + + The authentication method uses Active Directory Integrated. Use Active Directory Integrated to connect to a SQL Database using integrated Windows authentication. + 3 + + + The authentication method uses Active Directory Interactive. Use Active Directory Interactive to connect to a SQL Database with an interactive authentication flow. + 4 + + + The authentication method uses Active Directory Service Principal. Use Active Directory Service Principal to connect to a SQL Database using the client ID and secret of a service principal identity. + 5 + + + The authentication method uses Active Directory Device Code Flow. Use Active Directory Device Code Flow to connect to a SQL Database from devices and operating systems that do not provide a Web browser, using another device to perform interactive authentication. + 6 + + + The authentication method uses Active Directory Managed Identity. Use System Assigned or User Assigned Managed Identity to connect to SQL Database from Azure client environments that have enabled support for Managed Identity. For User Assigned Managed Identity, 'User Id' or 'UID' is required to be set to the "client ID" of the user identity. + 7 + + + Alias for "Active Directory Managed Identity" authentication method. Use System Assigned or User Assigned Managed Identity to connect to SQL Database from Azure client environments that have enabled support for Managed Identity. For User Assigned Managed Identity, 'User Id' or 'UID' is required to be set to the "client ID" of the user identity. + 8 + + + The authentication method uses Active Directory Default. Use this mode to connect to a SQL Database using multiple non-interactive authentication methods tried sequentially to acquire an access token. This method does not fallback to the "Active Directory Interactive" authentication method. + 9 + + + The authentication method uses Active Directory Workload Identity. Use a federated User Assigned Managed Identity to connect to SQL Database from Azure client environments that have enabled support for Workload Identity. The 'User Id' or 'UID' is required to be set to the "client ID" of the user identity. + 10 + + diff --git a/doc/snippets/Microsoft.Data.SqlClient/SqlAuthenticationParameters.xml b/doc/snippets/Microsoft.Data.SqlClient/SqlAuthenticationParameters.xml index 51fec0ae1f..7c409cdc5c 100644 --- a/doc/snippets/Microsoft.Data.SqlClient/SqlAuthenticationParameters.xml +++ b/doc/snippets/Microsoft.Data.SqlClient/SqlAuthenticationParameters.xml @@ -1,55 +1,59 @@ - - - - Represents AD authentication parameters passed by a driver to authentication providers. - - - One of the enumeration values that specifies the authentication method. - The server name. - The database name. - The resource URI. - The authority URI. - The user login name/ID. - The user password. - The connection ID. - The connection timeout value in seconds. - Initializes a new instance of the class using the specified authentication method, server name, database name, resource URI, authority URI, user login name/ID, user password, connection ID and connection timeout value. - - - Gets the authentication method. - The authentication method. - - - The resource URIs. - The resource URI. - - - Gets the authority URI. - The authority URI. - - - Gets the user login name/ID. - The user login name/ID. - - - Gets the user password. - The user password. - - - Gets the connection ID. - The connection ID. - - - Gets the server name. - The server name. - - - Gets the database name. - The database name. - - - Gets the connection timeout value. - The connection timeout value to be passed to Cancellation Token Source. - - + + + + + Represents AD authentication parameters passed by a driver to authentication providers. + + + + One of the enumeration values that specifies the authentication method. + The server name. + The database name. + The resource URI. + The authority URI. + The user login name/ID. + The user password. + The connection ID. + The connection timeout value in seconds. + + Initializes a new instance of the class using the specified authentication method, server name, database name, resource URI, authority URI, user login name/ID, user password, connection ID and connection timeout value. + + + + Gets the authentication method. + The authentication method. + + + The resource URIs. + The resource URI. + + + Gets the authority URI. + The authority URI. + + + Gets the user login name/ID. + The user login name/ID. + + + Gets the user password. + The user password. + + + Gets the connection ID. + The connection ID. + + + Gets the server name. + The server name. + + + Gets the database name. + The database name. + + + Gets the connection timeout value. + The connection timeout value to be passed to Cancellation Token Source. + + diff --git a/doc/snippets/Microsoft.Data.SqlClient/SqlAuthenticationProvider.xml b/doc/snippets/Microsoft.Data.SqlClient/SqlAuthenticationProvider.xml index 4f21b9626f..9b6b8699e6 100644 --- a/doc/snippets/Microsoft.Data.SqlClient/SqlAuthenticationProvider.xml +++ b/doc/snippets/Microsoft.Data.SqlClient/SqlAuthenticationProvider.xml @@ -1,22 +1,71 @@ - + - Defines the core behavior of authentication providers and provides a base class for derived classes. + Defines the core behavior of authentication providers and provides a base class for derived classes. - - - + Derived classes must provide a parameterless constructor if they can be instantiated from the app.config file. + + The following example demonstrates implementing a custom SqlAuthenticationProvider and providing the same to SqlClient for overriding Device Code Flow authentication mode: + + using System; + using System.Threading.Tasks; + using Microsoft.Identity.Client; + using Microsoft.Data.SqlClient; + + namespace CustomAuthenticationProviderExamples + { + /// <summary> + /// Example demonstrating creating a custom device code flow authentication provider and attaching it to the driver. + /// This is helpful for applications that wish to override the Callback for the Device Code Result implemented by the SqlClient driver. + /// </summary> + public class CustomDeviceCodeFlowAzureAuthenticationProvider : SqlAuthenticationProvider + { + public override async Task<SqlAuthenticationToken> AcquireTokenAsync(SqlAuthenticationParameters parameters) + { + string clientId = "my-client-id"; + string clientName = "My Application Name"; + string s_defaultScopeSuffix = "/.default"; + + string[] scopes = new string[] { parameters.Resource.EndsWith(s_defaultScopeSuffix) ? parameters.Resource : parameters.Resource + s_defaultScopeSuffix }; + + IPublicClientApplication app = PublicClientApplicationBuilder.Create(clientId) + .WithAuthority(parameters.Authority) + .WithClientName(clientName) + .WithRedirectUri("https://login.microsoftonline.com/common/oauth2/nativeclient") + .Build(); + + AuthenticationResult result = await app.AcquireTokenWithDeviceCode(scopes, + deviceCodeResult => CustomDeviceFlowCallback(deviceCodeResult)).ExecuteAsync(); + return new SqlAuthenticationToken(result.AccessToken, result.ExpiresOn); + } + + public override bool IsSupported(SqlAuthenticationMethod authenticationMethod) => + authenticationMethod.Equals(SqlAuthenticationMethod.ActiveDirectoryDeviceCodeFlow); + + private Task CustomDeviceFlowCallback(DeviceCodeResult result) + { + Console.WriteLine(result.Message); + return Task.FromResult(0); + } + } + + public class Program + { + public static void Main() + { + // Register our custom authentication provider class to override Active Directory Device Code Flow + SqlAuthenticationProvider.SetProvider(SqlAuthenticationMethod.ActiveDirectoryDeviceCodeFlow, new CustomDeviceCodeFlowAzureAuthenticationProvider()); + using (SqlConnection sqlConnection = new SqlConnection("Server=<myserver>.database.windows.net;Authentication=Active Directory Device Code Flow;Database=<db>;")) + { + sqlConnection.Open(); + Console.WriteLine("Connected successfully!"); + } + } + } + } + + @@ -26,10 +75,7 @@ The authentication method. Gets an authentication provider by method. - - The authentication provider or if not found. - - To be added. + The authentication provider or if not found. The authentication method. @@ -38,17 +84,20 @@ if the operation succeeded; otherwise, (for example, the existing provider disallows overriding). - To be added. The authentication method. - This method is called immediately before the provider is added to SQL drivers registry. - Avoid performing long-waiting tasks in this method, since it can block other threads from accessing the provider registry. + This method is called immediately before the provider is added to SQL drivers registry. + + Avoid performing long-waiting tasks in this method, since it can block other threads from accessing the provider registry. + The authentication method. - This method is called immediately before the provider is removed from the SQL drivers registry. - For example, this method is called when a different provider with the same authentication method overrides this provider in the SQL drivers registry. Avoid performing long-waiting task in this method, since it can block other threads from accessing the provider registry. + This method is called immediately before the provider is removed from the SQL drivers registry. + + For example, this method is called when a different provider with the same authentication method overrides this provider in the SQL drivers registry. Avoid performing long-waiting task in this method, since it can block other threads from accessing the provider registry. + The authentication method. @@ -56,13 +105,11 @@ if the specified authentication method is supported; otherwise, . - To be added. The Active Directory authentication parameters passed by the driver to authentication providers. Acquires a security token from the authority. Represents an asynchronous operation that returns the AD authentication token. - To be added. diff --git a/doc/snippets/Microsoft.Data.SqlClient/SqlAuthenticationToken.xml b/doc/snippets/Microsoft.Data.SqlClient/SqlAuthenticationToken.xml index 21818f4f5b..8e4efd0698 100644 --- a/doc/snippets/Microsoft.Data.SqlClient/SqlAuthenticationToken.xml +++ b/doc/snippets/Microsoft.Data.SqlClient/SqlAuthenticationToken.xml @@ -1,21 +1,25 @@ - - - - Represents an AD authentication token. - - - The access token. - The token expiration time. - Initializes a new instance of the class. - The parameter is or empty. - - - Gets the token expiration time. - The token expiration time. - - - Gets the token string. - The token string. - - + + + + Represents an AD authentication token. + + + The access token. + The token expiration time. + + Initializes a new instance of the class. + + + The parameter is or empty. + + + + Gets the token expiration time. + The token expiration time. + + + Gets the token string. + The token string. + + diff --git a/doc/snippets/Microsoft.Data.SqlClient/SqlBatch.xml b/doc/snippets/Microsoft.Data.SqlClient/SqlBatch.xml index e7e60639e8..e76631fe45 100644 --- a/doc/snippets/Microsoft.Data.SqlClient/SqlBatch.xml +++ b/doc/snippets/Microsoft.Data.SqlClient/SqlBatch.xml @@ -1,168 +1,306 @@ - - + - - - - and a , then adds multiple objects to the batch. It then executes the batch, creating a . The example reads through the results of the batch commands, writing them to the console. Finally, the example closes the and then the as the `using` blocks fall out of scope. - -[!code-csharp[SqlCommand Example#1](~/../sqlclient/doc/samples/SqlBatch_ExecuteReader.cs#1)] -]]> - - + + + The following example creates a and a , then adds multiple objects to the batch. It then executes the batch, creating a . The example reads through the results of the batch commands, writing them to the console. Finally, the example closes the and then the as the using blocks fall out of scope. + + + using Microsoft.Data.SqlClient; + + class Program + { + static void Main() + { + string str = "Data Source=(local);Initial Catalog=Northwind;" + + "Integrated Security=SSPI;Encrypt=False"; + RunBatch(str); + } + + static void RunBatch(string connString) + { + using var connection = new SqlConnection(connString); + connection.Open(); + + var batch = new SqlBatch(connection); + + const int count = 10; + const string parameterName = "parameter"; + for (int i = 0; i < count; i++) + { + var batchCommand = new SqlBatchCommand($"SELECT @{parameterName} as value"); + batchCommand.Parameters.Add(new SqlParameter(parameterName, i)); + batch.BatchCommands.Add(batchCommand); + } + + // Optionally Prepare + batch.Prepare(); + + var results = new List<int>(count); + using (SqlDataReader reader = batch.ExecuteReader()) + { + do + { + while (reader.Read()) + { + results.Add(reader.GetFieldValue<int>(0)); + } + } while (reader.NextResult()); + } + Console.WriteLine(string.Join(", ", results)); + } + } + + - - Initializes a new . - - - - - and a , then adds multiple objects to the batch. It then executes the batch, creating a . The example reads through the results of the batch commands, writing them to the console. Finally, the example closes the and then the as the `using` blocks fall out of scope. - -[!code-csharp[SqlCommand Example#1](~/../sqlclient/doc/samples/SqlBatch_ExecuteReader.cs#1)] -]]> - - + Initializes a new . + + + The following example creates a and a , then adds multiple objects to the batch. It then executes the batch, creating a . The example reads through the results of the batch commands, writing them to the console. Finally, the example closes the and then the as the using blocks fall out of scope. + + + + using Microsoft.Data.SqlClient; + + class Program + { + static void Main() + { + string str = "Data Source=(local);Initial Catalog=Northwind;" + + "Integrated Security=SSPI;Encrypt=False"; + RunBatch(str); + } + + static void RunBatch(string connString) + { + using var connection = new SqlConnection(connString); + connection.Open(); + + var batch = new SqlBatch(connection); + + const int count = 10; + const string parameterName = "parameter"; + for (int i = 0; i < count; i++) + { + var batchCommand = new SqlBatchCommand($"SELECT @{parameterName} as value"); + batchCommand.Parameters.Add(new SqlParameter(parameterName, i)); + batch.BatchCommands.Add(batchCommand); + } + + // Optionally Prepare + batch.Prepare(); + + var results = new List<lint>(count); + using (SqlDataReader reader = batch.ExecuteReader()) + { + do + { + while (reader.Read()) + { + results.Add(reader.GetFieldValue<int>(0)); + } + } while (reader.NextResult()); + } + Console.WriteLine(string.Join(", ", results)); + } + } + + - Initializes a new . - + Initializes a new . - A - - that represents the connection to an instance of SQL Server. + A that represents the connection to an instance of SQL Server. - The - - in which the - - executes. + The in which the executes. - - - - - - Gets or sets the - - used by this instance of the - - . + Gets or sets the used by this instance of the . - Gets or sets the within which the commands execute. + + Gets or sets the within which the commands execute. + The list of commands contained in the batch in a . - - - and a , then adds multiple objects to the batch. It then executes the batch, creating a . The example reads through the results of the batch commands, writing them to the console. Finally, the example closes the and then the as the `using` blocks fall out of scope. - -[!code-csharp[SqlCommand Example#1](~/../sqlclient/doc/samples/SqlBatch_ExecuteReader.cs#1)] -]]> - - + + + The following example creates a and a , then adds multiple objects to the batch. It then executes the batch, creating a . The example reads through the results of the batch commands, writing them to the console. Finally, the example closes the and then the as the using blocks fall out of scope. + + + using Microsoft.Data.SqlClient; + + class Program + { + static void Main() + { + string str = "Data Source=(local);Initial Catalog=Northwind;" + + "Integrated Security=SSPI;Encrypt=False"; + RunBatch(str); + } + + static void RunBatch(string connString) + { + using var connection = new SqlConnection(connString); + connection.Open(); + + var batch = new SqlBatch(connection); + + const int count = 10; + const string parameterName = "parameter"; + for (int i = 0; i < count; i++) + { + var batchCommand = new SqlBatchCommand($"SELECT @{parameterName} as value"); + batchCommand.Parameters.Add(new SqlParameter(parameterName, i)); + batch.BatchCommands.Add(batchCommand); + } + + // Optionally Prepare + batch.Prepare(); + + var results = new List<int>(count); + using (SqlDataReader reader = batch.ExecuteReader()) + { + do + { + while (reader.Read()) + { + results.Add(reader.GetFieldValue<int>(0)); + } + } while (reader.NextResult()); + } + Console.WriteLine(string.Join(", ", results)); + } + } + + - The list of commands contained in the batch in a - of - objects. + The list of commands contained in the batch in a of objects. - - - - Sends the - - to the - - and builds a - - . + Sends the to the and builds a . - - - and a , then adds multiple objects to the batch. It then executes the batch, creating a . The example reads through the results of the batch commands, writing them to the console. Finally, the example closes the and then the as the `using` blocks fall out of scope. - -[!code-csharp[SqlCommand Example#1](~/../sqlclient/doc/samples/SqlBatch_ExecuteReader.cs#1)] -]]> - - + + + The following example creates a and a , then adds multiple objects to the batch. It then executes the batch, creating a . The example reads through the results of the batch commands, writing them to the console. Finally, the example closes the and then the as the using blocks fall out of scope. + + + using Microsoft.Data.SqlClient; + + class Program + { + static void Main() + { + string str = "Data Source=(local);Initial Catalog=Northwind;" + + "Integrated Security=SSPI;Encrypt=False"; + RunBatch(str); + } + + static void RunBatch(string connString) + { + using var connection = new SqlConnection(connString); + connection.Open(); + + var batch = new SqlBatch(connection); + + const int count = 10; + const string parameterName = "parameter"; + for (int i = 0; i < count; i++) + { + var batchCommand = new SqlBatchCommand($"SELECT @{parameterName} as value"); + batchCommand.Parameters.Add(new SqlParameter(parameterName, i)); + batch.BatchCommands.Add(batchCommand); + } + + // Optionally Prepare + batch.Prepare(); + + var results = new List<int>(count); + using (SqlDataReader reader = batch.ExecuteReader()) + { + do + { + while (reader.Read()) + { + results.Add(reader.GetFieldValue<int>(0)); + } + } while (reader.NextResult()); + } + Console.WriteLine(string.Join(", ", results)); + } + } + + A token to cancel the asynchronous operation. - An asynchronous version of - - , which sends the - - to the - - and builds a - . + An asynchronous version of , which sends the to the and builds a . Exceptions will be reported via the returned Task object. A task representing the asynchronous operation. - An error occurred while executing the batch. - The value is invalid. - The cancellation token was canceled. This exception is stored into the returned task. + + An error occurred while executing the batch. + + + The value is invalid. + + + The cancellation token was canceled. This exception is stored into the returned task. + Gets the collection of objects. The commands contained within the batch. - Gets or sets the used by this . + + Gets or sets the used by this . + The connection to the data source. - Gets or sets the within which this object executes. - The transaction within which a batch of a ADO.NET data provider executes. The default value is a null reference ( in Visual Basic). + + Gets or sets the within which this object executes. + + + The transaction within which a batch of a ADO.NET data provider executes. The default value is a null reference ( in Visual Basic). + - Gets or sets the wait time (in seconds) before terminating the attempt to execute the batch and generating an error. - The time in seconds to wait for the batch to execute, which is in contract with the underlaying + + Gets or sets the wait time (in seconds) before terminating the attempt to execute the batch and generating an error. + + + The time in seconds to wait for the batch to execute, which is in contract with the underlying + - is generated if the assigned property value is less than 0. - - Note to implementers: it's recommended that 0 mean no timeout. - - ]]> + + An is generated if the assigned property value is less than 0. + + + Note to implementers: it's recommended that 0 mean no timeout. + - Attempts to cancel the execution of a . + + Attempts to cancel the execution of a . + - + If there is nothing to cancel, nothing happens. However, if there is a batch in process, and the attempt to cancel fails, no exception is generated. @@ -170,116 +308,134 @@ The following example creates a an A object. - Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. + + Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. + - An instance of , specifying options for batch execution and data retrieval. - Executes the batch against its connection, returning a which can be used to access the results. + + An instance of , specifying options for batch execution and data retrieval. + + + Executes the batch against its connection, returning a which can be used to access the results. + A object. - can be used to advance the reader to the next result set. - - > [!NOTE] - > This method benefits from , and all the expected exceptions of that method also apply here. - - ]]> + When the batch returns multiple result sets from different commands, can be used to advance the reader to the next result set. + + This method benefits from , and all the expected exceptions of that method also apply here. + - An error occurred while executing the batch. - The value is invalid. + + An error occurred while executing the batch. + + + The value is invalid. + One of the enumeration values that specifies options for batch execution and data retrieval. A token to cancel the asynchronous operation. - This implementation invokes the method and returns a completed task. The default implementation will return a cancelled task if passed an already cancelled cancellation token. - -This method accepts a cancellation token that can be used to request the operation to be cancelled early. + + This implementation invokes the method and returns a completed task. The default implementation will return a cancelled task if passed an already cancelled cancellation token. This method accepts a cancellation token that can be used to request the operation to be cancelled early. + A task representing the asynchronous operation. - , are still thrown synchronously. For the stored exceptions, see the exceptions thrown by . - - > [!NOTE] - > This method benefits from , and all the expected exceptions of that method also apply here. - -]]> + + For more information about asynchronous programming, see Asynchronous Programming. + + + This method stores in the task it returns all non-usage exceptions that the method's synchronous counterpart can throw. If an exception is stored into the returned task, that exception will be thrown when the task is awaited. Usage exceptions, such as , are still thrown synchronously. For the stored exceptions, see the exceptions thrown by . + + + This method benefits from , and all the expected exceptions of that method also apply here. + - The cancellation token was canceled. This exception is stored into the returned task. + + The cancellation token was canceled. This exception is stored into the returned task. + - Executes the batch against its connection object, returning the total number of rows affected across all the batch commands. + + Executes the batch against its connection object, returning the total number of rows affected across all the batch commands. + The total number of rows affected across all the batch commands. - to perform catalog operations (for example, querying the structure of a database or creating database objects such as tables), or to change the data in a database by executing UPDATE, INSERT, or DELETE statements. - - Although does not return any rows, any output parameters or return values mapped to parameters are populated with data. - - For UPDATE, INSERT, and DELETE statements, the return value is the total number of rows affected by the batch. If no UPDATE, INSERT, or DELETE statements are included in the batch, the return value is -1. - -> [!NOTE] -> This method benefits from , and all the expected exceptions of that method also apply here. - - ]]> + You can use to perform catalog operations (for example, querying the structure of a database or creating database objects such as tables), or to change the data in a database by executing UPDATE, INSERT, or DELETE statements. Although does not return any rows, any output parameters or return values mapped to parameters are populated with data. For UPDATE, INSERT, and DELETE statements, the return value is the total number of rows affected by the batch. If no UPDATE, INSERT, or DELETE statements are included in the batch, the return value is -1. + + This method benefits from , and all the expected exceptions of that method also apply here. + A token to cancel the asynchronous operation. - This is the asynchronous version of . - - The implementation invokes the method and returns a completed task. The default implementation will return a cancelled task if passed an already cancelled cancellation token. - - Do not invoke other methods and properties of the object until the returned Task is complete. + + This is the asynchronous version of . + The implementation invokes the method and returns a completed task. The default implementation will return a cancelled task if passed an already cancelled cancellation token. + Do not invoke other methods and properties of the object until the returned Task is complete. + A task representing the asynchronous operation. - , are still thrown synchronously. - -> [!NOTE] -> This method benefits from , and all the expected exceptions of that method also apply here. - -]]> + + For more information about asynchronous programming, see Asynchronous Programming. + + + If an exception is stored into the returned task, that exception will be thrown when the task is awaited. Usage exceptions, such as , are still thrown synchronously. + + + This method benefits from , and all the expected exceptions of that method also apply here. + An error occurred while executing the batch. ADO.NET Overview - The cancellation token was canceled. This exception is stored into the returned task. + + The cancellation token was canceled. This exception is stored into the returned task. + - Executes the batch and returns the first column of the first row in the first returned result set. All other columns, rows and resultsets are ignored. + + Executes the batch and returns the first column of the first row in the first returned result set. All other columns, rows and resultsets are ignored. + The first column of the first row in the first result set. - An error occurred while executing the batch. + + An error occurred while executing the batch. + A token to cancel the asynchronous operation. - An asynchronous version of , which executes the batch and returns the first column of the first row in the first returned result set. All other columns, rows and result sets are ignored. + + An asynchronous version of , which executes the batch and returns the first column of the first row in the first returned result set. All other columns, rows and result sets are ignored. + The first column of the first row in the first result set. - This method benefits from , and all the expected exceptions of that method also apply here. If an exception is stored into the returned task, that exception will be thrown when the task is awaited. Usage exceptions, such as , are still thrown synchronously. + + This method benefits from , and all the expected exceptions of that method also apply here. If an exception is stored into the returned task, that exception will be thrown when the task is awaited. Usage exceptions, such as , are still thrown synchronously. - An error occurred while executing the batch. - The cancellation token was canceled. This exception is stored into the returned task. + + An error occurred while executing the batch. + + + The cancellation token was canceled. This exception is stored into the returned task. + - Creates a prepared (or compiled) version of the batch, or of each of its commands, on the data source. + + Creates a prepared (or compiled) version of the batch, or of each of its commands, on the data source. + - An optional token to cancel the asynchronous operation. The default value is . - Asynchronously creates a prepared (or compiled) version of the batch, or of each of its commands, on the data source. + + An optional token to cancel the asynchronous operation. The default value is . + + + Asynchronously creates a prepared (or compiled) version of the batch, or of each of its commands, on the data source. + A representing the asynchronous operation. - This method stores in the task it returns all non-usage exceptions that the method's synchronous counterpart can throw. If an exception is stored into the returned task, that exception will be thrown when the task is awaited. Usage exceptions, such as , are still thrown synchronously. For the stored exceptions, see the exceptions thrown by . + + This method stores in the task it returns all non-usage exceptions that the method's synchronous counterpart can throw. If an exception is stored into the returned task, that exception will be thrown when the task is awaited. Usage exceptions, such as , are still thrown synchronously. For the stored exceptions, see the exceptions thrown by . - The cancellation token was canceled. This exception is stored into the returned task. + + The cancellation token was canceled. This exception is stored into the returned task. + From 5dc7b06e16705f6dcb8a0f437b28cd320ee2a719 Mon Sep 17 00:00:00 2001 From: Benjamin Russell Date: Thu, 5 Sep 2024 13:06:13 -0500 Subject: [PATCH 09/12] Reverting removal of the snippet files. (#2835) --- ...DAuthenticationCustomDeviceFlowCallback.cs | 30 ++++++++++ ...tionClientIdAzureAuthenticationProvider.cs | 26 +++++++++ ...viceCodeFlowAzureAuthenticationProvider.cs | 57 +++++++++++++++++++ 3 files changed, 113 insertions(+) create mode 100644 doc/samples/AADAuthenticationCustomDeviceFlowCallback.cs create mode 100644 doc/samples/ApplicationClientIdAzureAuthenticationProvider.cs create mode 100644 doc/samples/CustomDeviceCodeFlowAzureAuthenticationProvider.cs diff --git a/doc/samples/AADAuthenticationCustomDeviceFlowCallback.cs b/doc/samples/AADAuthenticationCustomDeviceFlowCallback.cs new file mode 100644 index 0000000000..d225f64ae8 --- /dev/null +++ b/doc/samples/AADAuthenticationCustomDeviceFlowCallback.cs @@ -0,0 +1,30 @@ +// +using System; +using System.Threading.Tasks; +using Microsoft.Identity.Client; +using Microsoft.Data.SqlClient; + +namespace CustomAuthenticationProviderExamples +{ + public class Program + { + public static void Main() + { + SqlAuthenticationProvider authProvider = new ActiveDirectoryAuthenticationProvider(CustomDeviceFlowCallback); + SqlAuthenticationProvider.SetProvider(SqlAuthenticationMethod.ActiveDirectoryDeviceCodeFlow, authProvider); + using (SqlConnection sqlConnection = new SqlConnection("Server=.database.windows.net;Authentication=Active Directory Device Code Flow;Database=;")) + { + sqlConnection.Open(); + Console.WriteLine("Connected successfully!"); + } + } + + private static Task CustomDeviceFlowCallback(DeviceCodeResult result) + { + // Provide custom logic to process result information and read device code. + Console.WriteLine(result.Message); + return Task.FromResult(0); + } + } +} +// diff --git a/doc/samples/ApplicationClientIdAzureAuthenticationProvider.cs b/doc/samples/ApplicationClientIdAzureAuthenticationProvider.cs new file mode 100644 index 0000000000..f206a1c29e --- /dev/null +++ b/doc/samples/ApplicationClientIdAzureAuthenticationProvider.cs @@ -0,0 +1,26 @@ +// +using System; +using Microsoft.Data.SqlClient; + +namespace CustomAuthenticationProviderExamples +{ + public class Program + { + public static void Main() + { + // Supported for all authentication modes supported by ActiveDirectoryAuthenticationProvider + ActiveDirectoryAuthenticationProvider provider = new ActiveDirectoryAuthenticationProvider(""); + if (provider.IsSupported(SqlAuthenticationMethod.ActiveDirectoryInteractive)) + { + SqlAuthenticationProvider.SetProvider(SqlAuthenticationMethod.ActiveDirectoryInteractive, provider); + } + + using (SqlConnection sqlConnection = new SqlConnection("Server=.database.windows.net;Authentication=Active Directory Interactive;Database=;")) + { + sqlConnection.Open(); + Console.WriteLine("Connected successfully!"); + } + } + } +} +// diff --git a/doc/samples/CustomDeviceCodeFlowAzureAuthenticationProvider.cs b/doc/samples/CustomDeviceCodeFlowAzureAuthenticationProvider.cs new file mode 100644 index 0000000000..e71c9af8d1 --- /dev/null +++ b/doc/samples/CustomDeviceCodeFlowAzureAuthenticationProvider.cs @@ -0,0 +1,57 @@ +// +using System; +using System.Threading.Tasks; +using Microsoft.Identity.Client; +using Microsoft.Data.SqlClient; + +namespace CustomAuthenticationProviderExamples +{ + /// + /// Example demonstrating creating a custom device code flow authentication provider and attaching it to the driver. + /// This is helpful for applications that wish to override the Callback for the Device Code Result implemented by the SqlClient driver. + /// + public class CustomDeviceCodeFlowAzureAuthenticationProvider : SqlAuthenticationProvider + { + public override async Task AcquireTokenAsync(SqlAuthenticationParameters parameters) + { + string clientId = "my-client-id"; + string clientName = "My Application Name"; + string s_defaultScopeSuffix = "/.default"; + + string[] scopes = new string[] { parameters.Resource.EndsWith(s_defaultScopeSuffix) ? parameters.Resource : parameters.Resource + s_defaultScopeSuffix }; + + IPublicClientApplication app = PublicClientApplicationBuilder.Create(clientId) + .WithAuthority(parameters.Authority) + .WithClientName(clientName) + .WithRedirectUri("https://login.microsoftonline.com/common/oauth2/nativeclient") + .Build(); + + AuthenticationResult result = await app.AcquireTokenWithDeviceCode(scopes, + deviceCodeResult => CustomDeviceFlowCallback(deviceCodeResult)).ExecuteAsync(); + return new SqlAuthenticationToken(result.AccessToken, result.ExpiresOn); + } + + public override bool IsSupported(SqlAuthenticationMethod authenticationMethod) => authenticationMethod.Equals(SqlAuthenticationMethod.ActiveDirectoryDeviceCodeFlow); + + private Task CustomDeviceFlowCallback(DeviceCodeResult result) + { + Console.WriteLine(result.Message); + return Task.FromResult(0); + } + } + + public class Program + { + public static void Main() + { + // Register our custom authentication provider class to override Active Directory Device Code Flow + SqlAuthenticationProvider.SetProvider(SqlAuthenticationMethod.ActiveDirectoryDeviceCodeFlow, new CustomDeviceCodeFlowAzureAuthenticationProvider()); + using (SqlConnection sqlConnection = new SqlConnection("Server=.database.windows.net;Authentication=Active Directory Device Code Flow;Database=;")) + { + sqlConnection.Open(); + Console.WriteLine("Connected successfully!"); + } + } + } +} +// From cf92a05fd5ba458c1001dcd4af1b5bfba93dde66 Mon Sep 17 00:00:00 2001 From: David Engel Date: Thu, 5 Sep 2024 11:30:55 -0700 Subject: [PATCH 10/12] Sample code improvements around token caching (#2821) --- doc/samples/AzureKeyVaultProviderExample.cs | 6 ++- ...VaultProviderWithEnclaveProviderExample.cs | 6 ++- ...viceCodeFlowAzureAuthenticationProvider.cs | 44 ++++++++++----- .../SqlConnection_AccessTokenCallback.cs | 53 +++++++++++++------ 4 files changed, 76 insertions(+), 33 deletions(-) diff --git a/doc/samples/AzureKeyVaultProviderExample.cs b/doc/samples/AzureKeyVaultProviderExample.cs index e16a9a63a7..5bd89bb2fd 100644 --- a/doc/samples/AzureKeyVaultProviderExample.cs +++ b/doc/samples/AzureKeyVaultProviderExample.cs @@ -79,11 +79,13 @@ public static void Main(string[] args) } } + // Maintain an instance of the ClientCredential object to take advantage of underlying token caching + private static ClientCredential clientCredential = new ClientCredential(s_clientId, s_clientSecret); + public static async Task AzureActiveDirectoryAuthenticationCallback(string authority, string resource, string scope) { var authContext = new AuthenticationContext(authority); - ClientCredential clientCred = new ClientCredential(s_clientId, s_clientSecret); - AuthenticationResult result = await authContext.AcquireTokenAsync(resource, clientCred); + AuthenticationResult result = await authContext.AcquireTokenAsync(resource, clientCredential); if (result == null) { throw new InvalidOperationException($"Failed to retrieve an access token for {resource}"); diff --git a/doc/samples/AzureKeyVaultProviderWithEnclaveProviderExample.cs b/doc/samples/AzureKeyVaultProviderWithEnclaveProviderExample.cs index 2091dab322..8b9423ffe8 100644 --- a/doc/samples/AzureKeyVaultProviderWithEnclaveProviderExample.cs +++ b/doc/samples/AzureKeyVaultProviderWithEnclaveProviderExample.cs @@ -81,11 +81,13 @@ static void Main(string[] args) } } + // Maintain an instance of the ClientCredential object to take advantage of underlying token caching + private static ClientCredential clientCredential = new ClientCredential(s_clientId, s_clientSecret); + public static async Task AzureActiveDirectoryAuthenticationCallback(string authority, string resource, string scope) { var authContext = new AuthenticationContext(authority); - ClientCredential clientCred = new ClientCredential(s_clientId, s_clientSecret); - AuthenticationResult result = await authContext.AcquireTokenAsync(resource, clientCred); + AuthenticationResult result = await authContext.AcquireTokenAsync(resource, clientCredential); if (result == null) { throw new InvalidOperationException($"Failed to retrieve an access token for {resource}"); diff --git a/doc/samples/CustomDeviceCodeFlowAzureAuthenticationProvider.cs b/doc/samples/CustomDeviceCodeFlowAzureAuthenticationProvider.cs index e71c9af8d1..57ab75b72c 100644 --- a/doc/samples/CustomDeviceCodeFlowAzureAuthenticationProvider.cs +++ b/doc/samples/CustomDeviceCodeFlowAzureAuthenticationProvider.cs @@ -1,8 +1,10 @@ // using System; +using System.Collections.Generic; +using System.Linq; using System.Threading.Tasks; -using Microsoft.Identity.Client; using Microsoft.Data.SqlClient; +using Microsoft.Identity.Client; namespace CustomAuthenticationProviderExamples { @@ -12,28 +14,46 @@ namespace CustomAuthenticationProviderExamples /// public class CustomDeviceCodeFlowAzureAuthenticationProvider : SqlAuthenticationProvider { + private const string clientId = "my-client-id"; + private const string clientName = "My Application Name"; + private const string s_defaultScopeSuffix = "/.default"; + + // Maintain a copy of the PublicClientApplication object to cache the underlying access tokens it provides + private static IPublicClientApplication pcApplication; + public override async Task AcquireTokenAsync(SqlAuthenticationParameters parameters) { - string clientId = "my-client-id"; - string clientName = "My Application Name"; - string s_defaultScopeSuffix = "/.default"; - string[] scopes = new string[] { parameters.Resource.EndsWith(s_defaultScopeSuffix) ? parameters.Resource : parameters.Resource + s_defaultScopeSuffix }; - IPublicClientApplication app = PublicClientApplicationBuilder.Create(clientId) - .WithAuthority(parameters.Authority) - .WithClientName(clientName) - .WithRedirectUri("https://login.microsoftonline.com/common/oauth2/nativeclient") + IPublicClientApplication app = pcApplication; + if (app == null) + { + pcApplication = app = PublicClientApplicationBuilder.Create(clientId) + .WithAuthority(parameters.Authority) + .WithClientName(clientName) + .WithRedirectUri("https://login.microsoftonline.com/common/oauth2/nativeclient") .Build(); + } + + AuthenticationResult result; + + try + { + IEnumerable accounts = await app.GetAccountsAsync(); + result = await app.AcquireTokenSilent(scopes, accounts.FirstOrDefault()).ExecuteAsync(); + } + catch (MsalUiRequiredException) + { + result = await app.AcquireTokenWithDeviceCode(scopes, + deviceCodeResult => CustomDeviceFlowCallback(deviceCodeResult)).ExecuteAsync(); + } - AuthenticationResult result = await app.AcquireTokenWithDeviceCode(scopes, - deviceCodeResult => CustomDeviceFlowCallback(deviceCodeResult)).ExecuteAsync(); return new SqlAuthenticationToken(result.AccessToken, result.ExpiresOn); } public override bool IsSupported(SqlAuthenticationMethod authenticationMethod) => authenticationMethod.Equals(SqlAuthenticationMethod.ActiveDirectoryDeviceCodeFlow); - private Task CustomDeviceFlowCallback(DeviceCodeResult result) + private static Task CustomDeviceFlowCallback(DeviceCodeResult result) { Console.WriteLine(result.Message); return Task.FromResult(0); diff --git a/doc/samples/SqlConnection_AccessTokenCallback.cs b/doc/samples/SqlConnection_AccessTokenCallback.cs index 3d9422f7d4..3477e8a4de 100644 --- a/doc/samples/SqlConnection_AccessTokenCallback.cs +++ b/doc/samples/SqlConnection_AccessTokenCallback.cs @@ -1,8 +1,11 @@ using System; -using System.Data; // -using Microsoft.Data.SqlClient; +using System.Collections.Concurrent; +using System.Threading; +using System.Threading.Tasks; +using Azure.Core; using Azure.Identity; +using Microsoft.Data.SqlClient; class Program { @@ -12,25 +15,41 @@ static void Main() Console.ReadLine(); } + const string defaultScopeSuffix = "/.default"; + + // Reuse credential objects to take advantage of underlying token caches + private static ConcurrentDictionary credentials = new ConcurrentDictionary(); + + // Use a shared callback function for connections that should be in the same connection pool + private static Func> myAccessTokenCallback = + async (authParams, cancellationToken) => + { + string scope = authParams.Resource.EndsWith(defaultScopeSuffix) + ? authParams.Resource + : $"{authParams.Resource}{defaultScopeSuffix}"; + + DefaultAzureCredentialOptions options = new DefaultAzureCredentialOptions(); + options.ManagedIdentityClientId = authParams.UserId; + + // Reuse the same credential object if we are using the same MI Client Id + AccessToken token = await credentials.GetOrAdd(authParams.UserId, new DefaultAzureCredential(options)).GetTokenAsync( + new TokenRequestContext(new string[] { scope }), + cancellationToken); + + return new SqlAuthenticationToken(token.Token, token.ExpiresOn); + }; + private static void OpenSqlConnection() { - const string defaultScopeSuffix = "/.default"; - string connectionString = GetConnectionString(); - DefaultAzureCredential credential = new(); + // (Optional) Pass a User-Assigned Managed Identity Client ID. + // This will ensure different MI Client IDs are in different connection pools. + string connectionString = "Server=myServer.database.windows.net;Encrypt=Mandatory;UserId=;"; - using (SqlConnection connection = new(connectionString) + using (SqlConnection connection = new SqlConnection(connectionString) { - AccessTokenCallback = async (authParams, cancellationToken) => - { - string scope = authParams.Resource.EndsWith(defaultScopeSuffix) - ? authParams.Resource - : $"{authParams.Resource}{defaultScopeSuffix}"; - AccessToken token = await credential.GetTokenAsync( - new TokenRequestContext([scope]), - cancellationToken); - - return new SqlAuthenticationToken(token.Token, token.ExpiresOn); - } + // The callback function is part of the connection pool key. Using a static callback function + // ensures connections will not create a new pool per connection just for the callback. + AccessTokenCallback = myAccessTokenCallback }) { connection.Open(); From 62af3b51318ebba36327aa61b014264fd57a4130 Mon Sep 17 00:00:00 2001 From: Javad Rahnama Date: Fri, 6 Sep 2024 11:16:27 -0700 Subject: [PATCH 11/12] Fix | Adding readme to nuget package (#2826) --- tools/specs/Microsoft.Data.SqlClient.nuspec | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/specs/Microsoft.Data.SqlClient.nuspec b/tools/specs/Microsoft.Data.SqlClient.nuspec index 0af6429457..8e67327853 100644 --- a/tools/specs/Microsoft.Data.SqlClient.nuspec +++ b/tools/specs/Microsoft.Data.SqlClient.nuspec @@ -9,6 +9,7 @@ MIT https://aka.ms/sqlclientproject dotnet.png + README.md The current data provider for SQL Server and Azure SQL databases. This has replaced System.Data.SqlClient. These classes provide access to SQL and encapsulate database-specific protocols, including tabular data stream (TDS). @@ -76,6 +77,7 @@ When using NuGet 3.x this package requires at least version 3.4. + From eb4c0f043bff30c7f3bb58704b41c73faef9d63b Mon Sep 17 00:00:00 2001 From: Malcolm Daigle Date: Mon, 9 Sep 2024 11:04:55 -0700 Subject: [PATCH 12/12] Advance column index to avoid double clean. (#2825) --- .../src/Microsoft/Data/SqlClient/TdsParser.cs | 34 +++- .../ColumnDecryptErrorTests.cs | 170 ++++++++++++++++++ .../TestFixtures/SQLSetupStrategy.cs | 4 + .../Setup/ColumnDecryptErrorTestTable.cs | 40 +++++ ....Data.SqlClient.ManualTesting.Tests.csproj | 2 + 5 files changed, 243 insertions(+), 7 deletions(-) create mode 100644 src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/ColumnDecryptErrorTests.cs create mode 100644 src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/TestFixtures/Setup/ColumnDecryptErrorTestTable.cs diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs index edeecb6c9f..2ec05846cf 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs @@ -6388,16 +6388,36 @@ internal TdsOperationStatus TryReadSqlValue(SqlBuffer value, SqlMetaDataPriv md, { if (stateObj is not null) { - // call to decrypt column keys has failed. The data wont be decrypted. - // Not setting the value to false, forces the driver to look for column value. - // Packet received from Key Vault will throws invalid token header. - if (stateObj.HasPendingData) + // Throwing an exception here circumvents the normal pending data checks and cleanup processes, + // so we need to ensure the appropriate state. Increment the _nextColumnDataToRead index because + // we already read the encrypted column data; Otherwise we'll double count and attempt to drain a + // corresponding number of bytes a second time. We don't want the rest of the pending data to + // interfere with future operations, so we must drain it. Set HasPendingData to false to indicate + // that we successfully drained the data. + + // The SqlDataReader also maintains a state called dataReady. We need to set that to false if we've + // drained the data off the connection. Otherwise, a consumer that catches the exception may + // continue to use the reader and will timeout waiting to read data that doesn't exist. + + // Order matters here. Must increment column before draining data. + // Update state objects after draining data. + + + + if (stateObj._readerState != null) { - // Drain the pending data now if setting the HasPendingData to false. - // SqlDataReader.TryCloseInternal can not drain if HasPendingData = false. - DrainData(stateObj); + stateObj._readerState._nextColumnDataToRead++; } + + DrainData(stateObj); + + if (stateObj._readerState != null) + { + stateObj._readerState._dataReady = false; + } + stateObj.HasPendingData = false; + } throw SQL.ColumnDecryptionFailed(columnName, null, e); } diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/ColumnDecryptErrorTests.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/ColumnDecryptErrorTests.cs new file mode 100644 index 0000000000..954d94ee7f --- /dev/null +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/ColumnDecryptErrorTests.cs @@ -0,0 +1,170 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections; +using System.Collections.Generic; +using Microsoft.Data.SqlClient.ManualTesting.Tests.AlwaysEncrypted.Setup; +using Microsoft.Data.SqlClient.ManualTesting.Tests.SystemDataInternals; +using Xunit; + +namespace Microsoft.Data.SqlClient.ManualTesting.Tests.AlwaysEncrypted +{ + public sealed class ColumnDecryptErrorTests : IClassFixture, IDisposable + { + private SQLSetupStrategyAzureKeyVault fixture; + + private readonly string tableName; + + public ColumnDecryptErrorTests(SQLSetupStrategyAzureKeyVault context) + { + fixture = context; + tableName = fixture.ColumnDecryptErrorTestTable.Name; + } + + /* + * This test ensures that column decryption errors and connection pooling play nicely together. + * When a decryption error is encountered, we expect the connection to be drained of data and + * properly reset before being returned to the pool. If this doesn't happen, then random bytes + * may be left in the connection's state. These can interfere with the next operation that utilizes + * the connection. + * + * We test that state is properly reset by triggering the same error condition twice. Routing column key discovery + * away from AKV toward a dummy key store achieves this. Each connection pulls from a pool of max + * size one to ensure we are using the same internal connection/socket both times. We expect to + * receive the "Failed to decrypt column" exception twice. If the state were not cleaned properly, + * the second error would be different because the TDS stream would be unintelligible. + * + * Finally, we assert that restoring the connection to AKV allows a successful query. + */ + [ConditionalTheory(typeof(DataTestUtility), nameof(DataTestUtility.IsTargetReadyForAeWithKeyStore), nameof(DataTestUtility.IsAKVSetupAvailable))] + [ClassData(typeof(TestQueries))] + public void TestCleanConnectionAfterDecryptFail(string connString, string selectQuery, int totalColumnsInSelect, string[] types) + { + // Arrange + Assert.False(string.IsNullOrWhiteSpace(selectQuery), "FAILED: select query should not be null or empty."); + Assert.True(totalColumnsInSelect <= 3, "FAILED: totalColumnsInSelect should <= 3."); + + using (SqlConnection sqlConnection = new SqlConnection(connString)) + { + sqlConnection.Open(); + + Table.DeleteData(tableName, sqlConnection); + + Customer customer = new Customer( + 45, + "Microsoft", + "Corporation"); + + DatabaseHelper.InsertCustomerData(sqlConnection, null, tableName, customer); + } + + + // Act - Trigger a column decrypt error on the connection + Dictionary keyStoreProviders = new() + { + { "AZURE_KEY_VAULT", new DummyKeyStoreProvider() } + }; + + String poolEnabledConnString = new SqlConnectionStringBuilder(connString) { Pooling = true, MaxPoolSize = 1 }.ToString(); + + using (SqlConnection sqlConnection = new SqlConnection(poolEnabledConnString)) + { + sqlConnection.Open(); + sqlConnection.RegisterColumnEncryptionKeyStoreProvidersOnConnection(keyStoreProviders); + + using SqlCommand sqlCommand = new SqlCommand(string.Format(selectQuery, tableName), + sqlConnection, null, SqlCommandColumnEncryptionSetting.Enabled); + + using SqlDataReader sqlDataReader = sqlCommand.ExecuteReader(); + + Assert.True(sqlDataReader.HasRows, "FAILED: Select statement did not return any rows."); + + while (sqlDataReader.Read()) + { + var error = Assert.Throws(() => DatabaseHelper.CompareResults(sqlDataReader, types, totalColumnsInSelect)); + Assert.Contains("Failed to decrypt column", error.Message); + } + } + + + // Assert + using (SqlConnection sqlConnection = new SqlConnection(poolEnabledConnString)) + { + sqlConnection.Open(); + sqlConnection.RegisterColumnEncryptionKeyStoreProvidersOnConnection(keyStoreProviders); + + using SqlCommand sqlCommand = new SqlCommand(string.Format(selectQuery, tableName), + sqlConnection, null, SqlCommandColumnEncryptionSetting.Enabled); + using SqlDataReader sqlDataReader = sqlCommand.ExecuteReader(); + + Assert.True(sqlDataReader.HasRows, "FAILED: Select statement did not return any rows."); + + while (sqlDataReader.Read()) + { + var error = Assert.Throws(() => DatabaseHelper.CompareResults(sqlDataReader, types, totalColumnsInSelect)); + Assert.Contains("Failed to decrypt column", error.Message); + } + } + + using (SqlConnection sqlConnection = new SqlConnection(poolEnabledConnString)) + { + sqlConnection.Open(); + + using SqlCommand sqlCommand = new SqlCommand(string.Format(selectQuery, tableName), + sqlConnection, null, SqlCommandColumnEncryptionSetting.Enabled); + using SqlDataReader sqlDataReader = sqlCommand.ExecuteReader(); + + Assert.True(sqlDataReader.HasRows, "FAILED: Select statement did not return any rows."); + + while (sqlDataReader.Read()) + { + DatabaseHelper.CompareResults(sqlDataReader, types, totalColumnsInSelect); + } + } + } + + + public void Dispose() + { + foreach (string connStrAE in DataTestUtility.AEConnStringsSetup) + { + using (SqlConnection sqlConnection = new SqlConnection(connStrAE)) + { + sqlConnection.Open(); + Table.DeleteData(fixture.ColumnDecryptErrorTestTable.Name, sqlConnection); + } + } + } + + private sealed class DummyKeyStoreProvider : SqlColumnEncryptionKeyStoreProvider + { + public override byte[] DecryptColumnEncryptionKey(string masterKeyPath, string encryptionAlgorithm, byte[] encryptedColumnEncryptionKey) + { + // Must be 32 to match the key length expected for the 'AEAD_AES_256_CBC_HMAC_SHA256' algorithm + return new byte[32]; + } + + public override byte[] EncryptColumnEncryptionKey(string masterKeyPath, string encryptionAlgorithm, byte[] columnEncryptionKey) + { + return new byte[32]; + } + } + } + + public class TestQueries : IEnumerable + { + public IEnumerator GetEnumerator() + { + foreach (string connStrAE in DataTestUtility.AEConnStrings) + { + yield return new object[] { connStrAE, @"select CustomerId, FirstName, LastName from [{0}] ", 3, new string[] { @"int", @"string", @"string" } }; + yield return new object[] { connStrAE, @"select CustomerId, FirstName from [{0}] ", 2, new string[] { @"int", @"string" } }; + yield return new object[] { connStrAE, @"select LastName from [{0}] ", 1, new string[] { @"string" } }; + } + } + IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); + } +} + diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/TestFixtures/SQLSetupStrategy.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/TestFixtures/SQLSetupStrategy.cs index 4d3c635684..2bc38d9930 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/TestFixtures/SQLSetupStrategy.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/TestFixtures/SQLSetupStrategy.cs @@ -21,6 +21,7 @@ public class SQLSetupStrategy : IDisposable public Table ApiTestTable { get; private set; } public Table BulkCopyAEErrorMessageTestTable { get; private set; } public Table BulkCopyAETestTable { get; private set; } + public Table ColumnDecryptErrorTestTable { get; private set; } public Table SqlParameterPropertiesTable { get; private set; } public Table DateOnlyTestTable { get; private set; } public Table End2EndSmokeTable { get; private set; } @@ -127,6 +128,9 @@ protected List CreateTables(IList columnEncryptionKe BulkCopyAETestTable = new BulkCopyAETestTable(GenerateUniqueName("BulkCopyAETestTable"), columnEncryptionKeys[0], columnEncryptionKeys[1]); tables.Add(BulkCopyAETestTable); + ColumnDecryptErrorTestTable = new ColumnDecryptErrorTestTable(GenerateUniqueName("ColumnDecryptErrorTestTable"), columnEncryptionKeys[0], columnEncryptionKeys[1]); + tables.Add(ColumnDecryptErrorTestTable); + SqlParameterPropertiesTable = new SqlParameterPropertiesTable(GenerateUniqueName("SqlParameterPropertiesTable")); tables.Add(SqlParameterPropertiesTable); diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/TestFixtures/Setup/ColumnDecryptErrorTestTable.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/TestFixtures/Setup/ColumnDecryptErrorTestTable.cs new file mode 100644 index 0000000000..0a16e0c3aa --- /dev/null +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/TestFixtures/Setup/ColumnDecryptErrorTestTable.cs @@ -0,0 +1,40 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace Microsoft.Data.SqlClient.ManualTesting.Tests.AlwaysEncrypted.Setup +{ + public class ColumnDecryptErrorTestTable : Table + { + private const string ColumnEncryptionAlgorithmName = @"AEAD_AES_256_CBC_HMAC_SHA_256"; + public ColumnEncryptionKey columnEncryptionKey1; + public ColumnEncryptionKey columnEncryptionKey2; + private bool useDeterministicEncryption; + + public ColumnDecryptErrorTestTable(string tableName, ColumnEncryptionKey columnEncryptionKey1, ColumnEncryptionKey columnEncryptionKey2, bool useDeterministicEncryption = false) : base(tableName) + { + this.columnEncryptionKey1 = columnEncryptionKey1; + this.columnEncryptionKey2 = columnEncryptionKey2; + this.useDeterministicEncryption = useDeterministicEncryption; + } + + public override void Create(SqlConnection sqlConnection) + { + string encryptionType = useDeterministicEncryption ? "DETERMINISTIC" : DataTestUtility.EnclaveEnabled ? "RANDOMIZED" : "DETERMINISTIC"; + string sql = + $@"CREATE TABLE [dbo].[{Name}] + ( + [CustomerId] [int] ENCRYPTED WITH (COLUMN_ENCRYPTION_KEY = [{columnEncryptionKey1.Name}], ENCRYPTION_TYPE = {encryptionType}, ALGORITHM = '{ColumnEncryptionAlgorithmName}'), + [FirstName] [nvarchar](50) COLLATE Latin1_General_BIN2 ENCRYPTED WITH (COLUMN_ENCRYPTION_KEY = [{columnEncryptionKey2.Name}], ENCRYPTION_TYPE = DETERMINISTIC, ALGORITHM = '{ColumnEncryptionAlgorithmName}'), + [LastName] [nvarchar](50) COLLATE Latin1_General_BIN2 ENCRYPTED WITH (COLUMN_ENCRYPTION_KEY = [{columnEncryptionKey2.Name}], ENCRYPTION_TYPE = DETERMINISTIC, ALGORITHM = '{ColumnEncryptionAlgorithmName}') + )"; + + using (SqlCommand command = sqlConnection.CreateCommand()) + { + command.CommandText = sql; + command.ExecuteNonQuery(); + } + } + + } +} diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/Microsoft.Data.SqlClient.ManualTesting.Tests.csproj b/src/Microsoft.Data.SqlClient/tests/ManualTests/Microsoft.Data.SqlClient.ManualTesting.Tests.csproj index 0ec61b5420..6de3141afa 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/Microsoft.Data.SqlClient.ManualTesting.Tests.csproj +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/Microsoft.Data.SqlClient.ManualTesting.Tests.csproj @@ -57,6 +57,7 @@ + @@ -73,6 +74,7 @@ +