Skip to content

Conversation

paulmedynski
Copy link
Contributor

Work in Progress.

- 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.

/// <include file='../../../../../../doc/snippets/Microsoft.Data.SqlClient/SqlAuthenticationParameters.xml' path='docs/members[@name="SqlAuthenticationParameters"]/SqlAuthenticationParameters/*'/>
public class SqlAuthenticationParameters
public class SqlAuthenticationParameters : SqlAuthenticationParametersBase
Copy link
Contributor

Choose a reason for hiding this comment

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

What about completely moving SqlAuthenticationParameters and SqlAuthenticationToken to MDS.Abstractions and using [TypeForwardedTo] instead?

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 think you're correct about SqlAuthenticationParameters. I would just make a new internal class for the Builder and update any code that calls it currently.

For SqlAuthenticationToken, it's constructor makes a policy decision specific to MDS that I don't think we want to impose generally. Because the MDS SqlAuthenticationToken is part of the public API, I can't rename it or change the constructor behaviour without breaking existing apps. Maybe that would be OK for a major version bump - I will discuss internally.

I think the same goes for SqlAuthenticationProvider. It contains 2 static functions that cannot move to Abstractions, and renaming it could similarily break apps calling those functions.

Copy link
Contributor

Choose a reason for hiding this comment

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

Thanks. I definitely agree with you on SqlAuthenticationProvider.

The policy decision on SqlAuthenticationToken seems to be that we can't hand an instance which represents an empty token to SqlClient. What do you think about keeping the policy decision in the constructor (so we guarantee that every instance represents a non-null, non-empty token value); allowing SqlAuthenticationProvider.AcquireTokenAsync to return a Task with a value of null if it wants to represent an empty token; and ensuring that the call sites in SqlClient reject null? This seems like it'd separate the policy reasonably well.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

You're correct - there doesn't seem to be a valid use case for a null or empty token, so I've moved that policy into Abstractions. Providers can throw from AcquireTokenAsync() if they would otherwise return one.

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.

Get-ChildItem *.dll -Path $(extractedNugetPath) -Recurse | ForEach-Object VersionInfo | Format-List
displayName: 'Verify "File Version" matches expected values for DLLs'
- powershell: |
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 removed the TestMicrosoftDataSqlClientVersion build property entirely. It was made redundant by MdsPackageVersion.

<FileVersion>$(AbstractionsAssemblyFileVersion)</FileVersion>
<Version>$(AbstractionsPackageVersion)</Version>

<DocumentationFile>$(Artifacts)/doc/$(TargetFramework)/$(AssemblyName).xml</DocumentationFile>
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 will figure out where to put the XML docs in a later PR. For now, they go somewhere ignored by git.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This enum was moved out of TdsEnums.cs as-is.

namespace Microsoft.Data.SqlClient;

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

Choose a reason for hiding this comment

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

This and the token class are sealed. There is no need for an app to derive from them.

string accessToken,
DateTimeOffset expiresOn)
{
if (string.IsNullOrEmpty(accessToken))
Copy link
Contributor Author

Choose a reason for hiding this comment

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

A null or empty token is meaningless, so I moved this policy decision out of MDS and into Abstractions. I think this is correct.


// Here we mimic how ADAL calculates hash for token. They use UTF8 instead of Unicode.
var originalTokenString = SqlAuthenticationToken.AccessTokenStringFromBytes(token.accessToken);
var originalTokenString = Encoding.Unicode.GetString(token.accessToken);
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is what AccessTokenStringFromBytes() used to do.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is what remained in MDS from the SqlAuthenticationParamaters implementation.

using System.IO;
using System.Reflection;

#nullable enable
Copy link
Contributor Author

Choose a reason for hiding this comment

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

You will see some changes below related to this.

/// <summary>
/// Convert from a SqlAuthenticationToken.
/// </summary>
internal SqlFedAuthToken(SqlAuthenticationToken token)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Moved from SqlAuthenticationToken, since conversion to a SqlFedAuthToken belongs here anyway.

$(ThisAssemblyClsCompliant) is false.
-->
<ThisAssemblyClsCompliantContent Condition="'$(ThisAssemblyClsCompliant)' != 'false'">
[assembly: System.CLSCompliant(true)]
Copy link
Contributor Author

Choose a reason for hiding this comment

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

These new config properties are necessary to avoid collisions now that MDS depends on 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).
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.

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 decided to see how things look if we move GetProvider() and SetProvider() from SqlAuthenticationProvider to SqlAuthenticationProviderManager. This is a breaking change, but it separates the provider API definition from the act of managing providers. It was a mistake to combine these two into the provider API originally. I feel liks this is a worthwhile breaking change, and it will only affect apps that were managing providers explicitly via the get/set methods.

If we don't like this change, I can easily revert since it is all in a single commit.

Copy link
Contributor

Choose a reason for hiding this comment

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

In my opinion the API split itself makes sense (provided the breaking change is acceptable.) The class itself is currently halfway between being a completely static class and a class with a singleton instance, and if it's going to be exposed then I think it'd be best to settle on one approach or the other.

I've got one or two other comments, but they're not central to the public API; it's up to you whether they get pushed out to a later preview.

  • AuthenticationEnumFromString overlaps with SqlConnectionStringBuilder's parsing logic, and if the constants line up then we might be able to simplify by using that instead.
  • SetProvider currently iterates over a HashSet to perform a search for the authentication method; it can just use Contains instead.

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.

2 participants