Skip to content

Conversation

@paulmedynski
Copy link
Contributor

@paulmedynski paulmedynski commented Oct 10, 2025

Overview

This PR contains changes to move the ActiveDirectoryAuthenticationProvider out of the MDS package and into the new Azure package. Please refer to the design here:

MDS Azure Extension Design

This PR is only concerned with moving the provider code out of MDS and creating the necessary base classes and types in the Abstractions package, which includes:

  • Creation of base classes/types in Abstractions related to the SQL authentication provider APIs.
  • Move of the ActiveDirectoryAuthenticationProvider.cs file into the Azure package.
  • Creation of the Azure package and related PR/CI pipelines.
  • Targeted updates/improvements due to blast radius/fallout of the above.

Future PRs will address:

  • Proper documentation (API, samples, reference).
  • Dependency updates.
  • Terminology modernization.
  • String localization.
  • Code refactoring/improvements.
  • Addition of a synchronous AcquireToken() method.
  • Separation of existing tests out of the MDS project and into the Azure project.
  • Addition of unit tests and improved integration tests.
  • New tests in the MDS project to confirm the authentication provider management logic.
  • Any additional issues we come up with that aren't directly related to the move.

This builds on the previous 2 PRs:

Testing

All existing tests in the MDS project are passing. This confirms that the move didn't break anything that is currently being tested.

Copy link
Contributor Author

@paulmedynski paulmedynski left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Commentary for reviewers and some TODOs for me.

Copy link
Contributor Author

@paulmedynski paulmedynski left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Commentary for reviewers.

Base automatically changed from dev/paul/azure-split/abstractions-pipelines to feat/azure-split October 16, 2025 16:23
@paulmedynski paulmedynski force-pushed the dev/paul/azure-split/authentication branch from ddc22a7 to 71fd319 Compare October 16, 2025 19:57
@paulmedynski paulmedynski force-pushed the dev/paul/azure-split/authentication branch from 71fd319 to 283f241 Compare October 16, 2025 20:04
@codecov
Copy link

codecov bot commented Oct 20, 2025

Codecov Report

❌ Patch coverage is 77.77778% with 54 lines in your changes missing coverage. Please review.
⚠️ Please upload report for BASE (feat/azure-split@287309f). Learn more about missing BASE report.

Files with missing lines Patch % Lines
...Data/SqlClient/SqlAuthenticationProviderManager.cs 78.72% 20 Missing ⚠️
...crosoft/Data/SqlClient/SqlInternalConnectionTds.cs 61.76% 13 Missing ⚠️
...crosoft/Data/SqlClient/SqlInternalConnectionTds.cs 61.76% 13 Missing ⚠️
...ta/SqlClient/SqlAuthenticationParametersBuilder.cs 79.41% 7 Missing ⚠️
...Microsoft/Data/SqlClient/TdsParserHelperClasses.cs 95.45% 1 Missing ⚠️
Additional details and impacted files
@@                 Coverage Diff                 @@
##             feat/azure-split    #3680   +/-   ##
===================================================
  Coverage                    ?   76.78%           
===================================================
  Files                       ?      269           
  Lines                       ?    45029           
  Branches                    ?        0           
===================================================
  Hits                        ?    34574           
  Misses                      ?    10455           
  Partials                    ?        0           
Flag Coverage Δ
addons 90.82% <ø> (?)
netcore 76.63% <75.11%> (?)
netfx 76.14% <80.38%> (?)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

- Removed addition of PDBs from <AllowedOutputExtensionsInPackageBuildOutputFolder>.
- Removed MDS package ref dependency on Abstractions until pipelines are ready.
- Renamed AbstractionsPackage to Abstractions in targets.
- Updated BUILDGUIDE based on project ref behaviour.
- Added feature branches to CI pipeline triggers.
- Added missing/incomplete paths to the trigger.
- Added dev/* branches to the CI triggers so PRs that target other dev/ branches can run CI.
- Added missing MdsPackageVersion property to signed build pipeline job.
- Commented-out failing NuGet tool installer task.
- Re-ordered Guardian analysis step _before_ build step to avoid clobbering versioned DLLs.
- Added MDS package version to AKV build/package steps.
- Restored AKV nuspec ReferenceType property for AKV Official builds.
- Explicitly building tooling before analysis.
- Fixing validation steps to match XML props files.
- Added PR automation triggers, and documented other pipeline sections.
- Added ReferenceType throughout the MDS/AKV CI build steps.
- Added NuGet.config update to main CI build step for Package reference mode.
- Swapped Abstractions download and NuGet.config update to ensure packages/ exists before attempting to re-configure NuGet.
- Clean target no longer removes packages/
- Uncommented package refs to Abstractions.
- Added separate MDS and AKV project builds to support Package mode.
- Added $ReferenceType$ property to MDS .nuspec like it is for AKV.
- Removed obsolete version variables from merge conflict.
- Adding $ReferenceType$ back to AKV nuspec.
- Moved SqlAuthenticationProvider and friends into Abstractions.
- Moved ActiveDirectoryAuthenticationProvider into a new Azure package.
- Moved a bunch of docs into Abstractions and Azure projects.
- Updated Abstractions classes to be abstract with minimal implementation.
- Added back the implementations to MDS.
- Re-worked some of the docs.
- SqlAuthentication* classes separated out into Base classes in Abstractions.
- Updated docs accordingly.
- MDS compiles.
- Some Azure package code moved, but not compiling.
- Added an exception class for authentication errors.
- Enabled XML doc compilation and validation.
- Updated MDS to handle SqlAuthenticationProviderException instead of MSAL exceptions.
- Removed Azure.Identity from MDS.
- Got existing tests compiling using the new Azure package.
- Added Azure package build targets.
- Updated docs related to ReferenceType
- Got all projects properly adhering to Package reference type.
- Removed TestMicrosoftDataSqlClientVersion in favour of MdsPackageVersion.
- Fixed tools restore from build.proj.
- Fixed missing using for dummy auth provider.
- Fixed obsolete warnings for password auth.
- Moved SqlAuthenticationParameters entirely into Abstractions, avoiding an empty base class.
- Moved SqlAuthenticationToken entirely into Abstractions.
- Moved SqlAuthenticationProvider entirely into Abstractions.
- Removed SqlAuthenticationProviderBase.
- Exposed SqlAuthenticationProviderManager as a public API in MDS.
- Moved SetProvider() and GetProvider() to the Manager where they should have been all along (Breaking Change).
- Added catch-all exception handlers in prep for proper analysis and specific exception handling.
- Some improvements to avoid meaningless nulls.
- Added PR/CI pipeline support for the Azure package.
- Fixed Abstractions download path.
- Updated SqlAuthenticationProviderException to use Method instead of Action.
- Fixed NRE in SqlException.
- Fixed SqlAuthenticationProviderException use in MDS.
- Added chaining Add() to SqlErrorCollection.
- Added a useful message when _fedAuthToken is null after attempting to acquire a token.
- Fixed auth provider error handling to mimic the old code.
- Removing unnecessary database checks that are hanging forever.
- Fixed timestamp truncation from long to uint causing cached tokens to be erroneously expired.
@paulmedynski paulmedynski force-pushed the dev/paul/azure-split/authentication branch from 87be738 to 224a316 Compare October 20, 2025 15:00
Copy link
Contributor Author

@paulmedynski paulmedynski left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Commentary for reviewers, and a few things for me to fix.

@paulmedynski paulmedynski marked this pull request as ready for review October 20, 2025 15:58
@paulmedynski paulmedynski requested a review from a team as a code owner October 20, 2025 15:58
Copy link
Contributor

@David-Engel David-Engel left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Partial 45/89 review

…r to maintain API for now.

- Addressed review comments.
- Added some config improvements to xUnit runners.
@paulmedynski paulmedynski added this to the 7.0.0-preview3 milestone Oct 21, 2025
- Reverted SqlAuthenticationParameters authenticationTimeout constructor argument to its original name connectionTimeout and added docs explaining why.
- Moved some tests around to get access to internals and to compile everywhere.
Copy link
Contributor Author

@paulmedynski paulmedynski left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I reverted all of the previous public API changes and left notes about what we may want to bring back in the future.

Copy link
Contributor

@apoorvdeshmukh apoorvdeshmukh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need any updates to the samples such as doc/samples/AADAuthenticationCustomDeviceFlowCallback.cs and doc/samples/ApplicationClientIdAzureAuthenticationProvider.cs?

@paulmedynski
Copy link
Contributor Author

Perhaps - all documentation activities are deferred to future PRs.

cheenamalhotra
cheenamalhotra previously approved these changes Nov 6, 2025
Copy link
Member

@cheenamalhotra cheenamalhotra left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor comments, generally we can take it forward and address remaining work in future PRs.

<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFrameworks>net462;net8.0;net9.0</TargetFrameworks>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you planning to use common variables for target frameworks as done in MDS tests in another PR?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That sounds like a great idea after the .NET and .NET Framework MDS projects merge, and we have the same set of target frameworks for all of our projects.


<!-- Conditional Package References -->
<ItemGroup Condition="'$(ReferenceType)' == 'Package'">
<PackageReference Include="Microsoft.Data.SqlClient" />
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see you removed the packages.props in above directory.. What version will be picked up here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MSBuild walks up the directory tree until it finds a Directory.Packages.props file, so this project will find this props file:

src/Directory.Packages.props

That's the same one everything else in the src directory uses. It specifies the MDS package version as:

    <PackageVersion
      Include="Microsoft.Data.SqlClient"
      Version="$(MdsPackageVersion)" />

The $(MdsPackageVersion) is explicitly set by all pipelines, so it's either a CI/PR build number, or the official values found in YAML or ADO Libraries. For command-line/IDE builds, we use a default value chosen by Version.props:

    <MdsPackageVersion Condition="'$(MdsPackageVersion)' == ''">$(MdsVersionDefault).$(BuildNumber)-dev</MdsPackageVersion>

Copy link
Contributor

@benrr101 benrr101 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall I'm only really complaining about the structure tests to make it clearer with less words. But I will accept things like "oh we'll fix those later"

<PropertyGroup>
<AssemblyName>Microsoft.Data.SqlClient.Extensions.Abstractions</AssemblyName>
<RootNamespace>Microsoft.Data.SqlClient.Extensions.Abstractions</RootNamespace>
<RootNamespace>$(AssemblyName)</RootNamespace>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please make sure that this is accurate for the file path and the namespaces of the files. Some IDEs will complain if the namespaces don't match the path, and I agree with that preference. That's why a while back I made a change to remove the root namespace from MDS projects (since the paths replicate the full namespace, and contain things outside the MDS namespace).

// 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;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Calling back to the root namespace comment, since this is in the Microsoft.Data.SqlClient namespace, this will raise a warning in some IDEs. Since the root namesapce is Microsoft.Data.SqlClient.Extensions.Abstractions, the expected namespace for this class would be Microsoft.Data.SqlClient.Extensions.Abstractions. But, since this is a public API, we can't change the namespace without it being a breaking change. Soooo, I'd recommend making the root namespace either blank (and putting the files in a Microsoft.Data.SqlClient folder) or making the root namespace Microsoft.Data.SqlClient (and all abstraction files in an Extensions.Abstractions folder)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's defer project directory structure discussions/changes until after the MDS project merge. We already have a mishmash of approaches and we need to do a full sweep anyway.

/// <include file='../doc/SqlAuthenticationMethod.xml' path='docs/members[@name="SqlAuthenticationMethod"]/ActiveDirectoryPassword/*'/>
[Obsolete("ActiveDirectoryPassword is deprecated, use a more secure authentication method. See https://aka.ms/SqlClientEntraIDAuthentication for more details.")]
// Obsoleted with MDS 7.0.0; to be removed at least 2 major versions later.
ActiveDirectoryPassword,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Introducing aliases for "Entra*" might be a good idea at ... some point.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed, but not today :)

public string DatabaseName { get; }

/// <include file='../doc/SqlAuthenticationParameters.xml' path='docs/members[@name="SqlAuthenticationParameters"]/ConnectionTimeout/*'/>
//
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will cause some grumbling from some IDEs... but I can't think of a good alternative that doesn't inject our internal comments into public docs.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shrug - I can't imagine why an IDE would grumble about XML and normal comments appearing together. They serve different purposes.

public int ConnectionTimeout { get; }

/// <include file='../doc/SqlAuthenticationParameters.xml' path='docs/members[@name="SqlAuthenticationParameters"]/ctor/*'/>
public SqlAuthenticationParameters(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Constructors then properties :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I avoided style changes like this on purpose to make diffs to the originals sane.

shouldRetry,
retryPeriod,
message,
null);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: for constants like null, it would be very nice to use the argument label


namespace Microsoft.Data.SqlClient.Extensions.Abstractions.Test;

// Tests for the obsolete SqlAuthenticationProvider.GetProvider and SetProvider
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you want to add comment blocks to test files, I won't complain, but please use xmldocs

// Test that GetProvider fails predictably when the MDS assembly can't be
// found.
[Fact]
public void GetProvider()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm gonna sound like a broken, pedantic but this is why it's important to layout the stages of a test, and use descriptive names for the tests. At first glance, I'd assume this test verifies that a provider can be gotten successfully. And at second glance, I'd assume that there's actually two test cases in here.

So, I'd recommend rewriting as

[Fact]
public void GetProvider_MdsMissing_ReturnsNull()
{
   // Precondition
   // - Ensure MDS really doesn't exist in the working path
   Assert.Throws<FileNotFoundException>(() => Assembly.Load("Microsoft.Data.SqlClient"));

   // Act
   var result = SqlAuthenticationProvider.GetProvider(SqlAuthenticationMethod.ActiveDirectoryInteractive);

   // Assert
   Assert.Null(result);
}

And with these changes, we know at a glance:

  • What the test does (without resorting to reading comments - or writing them!)
  • Which part is a pre-condition of the test passing
  • Which part is the action
  • Which part is the validation

I know it's more total lines, but it really does help make it easier to figure out tests at-a-glance. And considering most tests will sit for a loooong time without being looked at, we want future generations to have the easiest time understanding unit tests as possible.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll move the precondition out into a constructor.

IMO, introducing variables just to follow a pattern is a recipe for a botched test. There are certainly conditions where you need to do a few things and then check state or results. This isn't one of those cases though.

@@ -0,0 +1,27 @@
<Project Sdk="Microsoft.NET.Sdk">
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd still personally prefer it if test projects go in the root /test/ rather than under the project. But, we can argue about that later.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We definitely need a consistent approach - TBD!

EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Azure", "Azure", "{A20114E1-82D8-903A-C389-726EB4FD943F}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{0D2F834B-6D91-18D0-3F09-672D448751BD}"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oof, yeah we're gonna have to argue about this

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's the result of:

$ cd src
$ dotnet sln add Microsoft.Data.SqlClient.Extensions/Azure/src/Azure.csproj
$ dotnet sln add Microsoft.Data.SqlClient.Extensions/Azure/test/Azure.Test.csproj

I assume dotnet knows what it's doing.

  - Added XML docs throughout.
  - Improved unit test names.
  - Removed <RootNamespace> from project files.
- Removed unnecessary sample files from the Abstractions project.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

9 participants