Skip to content

Commit c81212d

Browse files
committed
Add support for AadWorkloadIdentity authentication mode.
1 parent abaa3ee commit c81212d

8 files changed

Lines changed: 70 additions & 39 deletions

PSql.Tests/Tests.Unit/AzureAuthenticationModeExtensionsTests.cs

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,16 @@ namespace PSql.Tests.Unit;
99
public class AzureAuthenticationModeExtensionsTests
1010
{
1111
[Test]
12-
[TestCase(SqlPassword , "Sql Password" )]
13-
[TestCase(AadPassword , "Active Directory Password" )]
14-
[TestCase(AadIntegrated , "Active Directory Integrated" )]
15-
[TestCase(AadInteractive , "Active Directory Interactive" )]
16-
[TestCase(AadServicePrincipal , "Active Directory Service Principal")]
17-
[TestCase(AadDeviceCodeFlow , "Active Directory Device Code Flow" )]
18-
[TestCase(AadManagedIdentity , "Active Directory Managed Identity" )]
19-
[TestCase(AadDefault , "Active Directory Default" )]
20-
[TestCase(-1 , null )]
12+
[TestCase(SqlPassword, "Sql Password" )]
13+
[TestCase(AadPassword, "Active Directory Password" )]
14+
[TestCase(AadIntegrated, "Active Directory Integrated" )]
15+
[TestCase(AadInteractive, "Active Directory Interactive" )]
16+
[TestCase(AadServicePrincipal, "Active Directory Service Principal")]
17+
[TestCase(AadDeviceCodeFlow, "Active Directory Device Code Flow" )]
18+
[TestCase(AadManagedIdentity, "Active Directory Managed Identity" )]
19+
[TestCase(AadDefault, "Active Directory Default" )]
20+
[TestCase(AadWorkloadIdentity, "Active Directory Workload Identity")]
21+
[TestCase(-1, null )]
2122
public void RenderForConnectionString(AzureAuthenticationMode mode, string? value)
2223
{
2324
mode.RenderForConnectionString().ShouldBe(value);

PSql.Tests/Tests.Unit/AzureSqlContextTests.cs

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ private const string
2323
Auth_AadDeviceCodeFlow = @"Authentication=""Active Directory Device Code Flow"";",
2424
Auth_AadManagedIdentity = @"Authentication=""Active Directory Managed Identity"";",
2525
Auth_AadDefault = @"Authentication=""Active Directory Default"";",
26+
Auth_AadWorkloadIdentity = @"Authentication=""Active Directory Workload Identity"";",
2627
UserName = "User ID=user;",
2728
Password = "Password=pass;";
2829

@@ -413,12 +414,13 @@ public void GetConnectionString_ExplicitDatabase_Parameter()
413414
}
414415

415416
[Test]
416-
[TestCase(Default, Auth_AadIntegrated)]
417-
[TestCase(AadIntegrated, Auth_AadIntegrated)]
418-
[TestCase(AadInteractive, Auth_AadInteractive)]
419-
[TestCase(AadDeviceCodeFlow, Auth_AadDeviceCodeFlow)]
420-
[TestCase(AadManagedIdentity, Auth_AadManagedIdentity)] // credential is optional
421-
[TestCase(AadDefault, Auth_AadDefault)] // credential is optional
417+
[TestCase(Default, Auth_AadIntegrated)]
418+
[TestCase(AadIntegrated, Auth_AadIntegrated)]
419+
[TestCase(AadInteractive, Auth_AadInteractive)]
420+
[TestCase(AadDeviceCodeFlow, Auth_AadDeviceCodeFlow)]
421+
[TestCase(AadManagedIdentity, Auth_AadManagedIdentity)] // credential is optional
422+
[TestCase(AadDefault, Auth_AadDefault)] // credential is optional
423+
[TestCase(AadWorkloadIdentity, Auth_AadWorkloadIdentity)] // credential is optional
422424
public void GetConnectionString_NoCredential(AzureAuthenticationMode mode, string fragment)
423425
{
424426
var context = new AzureSqlContext
@@ -447,6 +449,7 @@ public void GetConnectionString_NoCredential(AzureAuthenticationMode mode, strin
447449
[TestCase(AadDeviceCodeFlow )]
448450
[TestCase(AadManagedIdentity )] // credential is optional
449451
[TestCase(AadDefault )] // credential is optional
452+
[TestCase(AadWorkloadIdentity)] // credential is optional
450453
public void GetConnectionString_NoCredential_Unsupported(AzureAuthenticationMode mode)
451454
{
452455
var context = new AzureSqlContext
@@ -488,15 +491,16 @@ public void GetConnectionString_NoCredential_Required(AzureAuthenticationMode mo
488491
}
489492

490493
[Test]
491-
[TestCase(Default, UserName + Password)]
492-
[TestCase(SqlPassword, UserName + Password)]
493-
[TestCase(AadPassword, Auth_AadPassword + UserName + Password)]
494-
[TestCase(AadIntegrated, Auth_AadIntegrated )]
495-
[TestCase(AadInteractive, Auth_AadInteractive )]
496-
[TestCase(AadServicePrincipal, Auth_AadServicePrincipal + UserName + Password)]
497-
[TestCase(AadDeviceCodeFlow, Auth_AadDeviceCodeFlow )]
498-
[TestCase(AadManagedIdentity, Auth_AadManagedIdentity + UserName )]
499-
[TestCase(AadDefault, Auth_AadDefault + UserName )]
494+
[TestCase(Default, UserName + Password)]
495+
[TestCase(SqlPassword, UserName + Password)]
496+
[TestCase(AadPassword, Auth_AadPassword + UserName + Password)]
497+
[TestCase(AadIntegrated, Auth_AadIntegrated )]
498+
[TestCase(AadInteractive, Auth_AadInteractive )]
499+
[TestCase(AadServicePrincipal, Auth_AadServicePrincipal + UserName + Password)]
500+
[TestCase(AadDeviceCodeFlow, Auth_AadDeviceCodeFlow )]
501+
[TestCase(AadManagedIdentity, Auth_AadManagedIdentity + UserName )]
502+
[TestCase(AadDefault, Auth_AadDefault + UserName )]
503+
[TestCase(AadWorkloadIdentity, Auth_AadWorkloadIdentity + UserName )]
500504
public void GetConnectionString_ExplicitCredential(AzureAuthenticationMode mode, string fragment)
501505
{
502506
var context = new AzureSqlContext

PSql.Tests/Tests.Unit/SqlClientVersionExtensionsTests.cs

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -10,21 +10,22 @@ namespace PSql;
1010
public class SqlClientVersionExtensionsTests
1111
{
1212
[Test]
13-
// 2.1 1.1
14-
// MODE 5 4 3 : 2 : 1 L
15-
[TestCase(Default, 0b_1_1_1_1_1_1_1_0)]
16-
[TestCase(SqlPassword, 0b_1_1_1_1_1_1_1_0)]
17-
[TestCase(AadPassword, 0b_1_1_1_1_1_1_1_0)]
18-
[TestCase(AadIntegrated, 0b_1_1_1_1_1_1_1_0)]
19-
[TestCase(AadInteractive, 0b_1_1_1_1_1_1_1_0)]
20-
[TestCase(AadServicePrincipal, 0b_1_1_1_1_1_0_0_0)]
21-
[TestCase(AadDeviceCodeFlow, 0b_1_1_1_1_0_0_0_0)]
22-
[TestCase(AadManagedIdentity, 0b_1_1_1_1_0_0_0_0)]
23-
[TestCase(AadDefault, 0b_1_1_1_0_0_0_0_0)]
24-
[TestCase(-1, 0b_0_0_0_0_0_0_0_0)]
13+
// MAJOR: 5 5 4 3 2 2 1 1
14+
// MODE MINOR: 2 0 0 0 1 0 1 0 Legacy
15+
[TestCase(Default, 0b_1_1_1_1_1_1_1_1_0)]
16+
[TestCase(SqlPassword, 0b_1_1_1_1_1_1_1_1_0)]
17+
[TestCase(AadPassword, 0b_1_1_1_1_1_1_1_1_0)]
18+
[TestCase(AadIntegrated, 0b_1_1_1_1_1_1_1_1_0)]
19+
[TestCase(AadInteractive, 0b_1_1_1_1_1_1_1_1_0)]
20+
[TestCase(AadServicePrincipal, 0b_1_1_1_1_1_1_0_0_0)]
21+
[TestCase(AadDeviceCodeFlow, 0b_1_1_1_1_1_0_0_0_0)]
22+
[TestCase(AadManagedIdentity, 0b_1_1_1_1_1_0_0_0_0)]
23+
[TestCase(AadDefault, 0b_1_1_1_1_0_0_0_0_0)]
24+
[TestCase(AadWorkloadIdentity, 0b_1_0_0_0_0_0_0_0_0)]
25+
[TestCase(-1, 0b_0_0_0_0_0_0_0_0_0)]
2526
public void SupportsAuthenticationMode(AzureAuthenticationMode mode, long bitmap)
2627
{
27-
for (var version = Legacy; version < Mds5; version++)
28+
for (var version = Legacy; version < Latest; version++)
2829
{
2930
var expected = (bitmap & 1) != 0;
3031

PSql/Data/AzureAuthenticationMode.cs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ public enum AzureAuthenticationMode // ~> M.D.S.SqlAuthenticationMethod
8585
/// <remarks>
8686
/// For a user-assigned managed identity,
8787
/// the <see cref="SqlContext.Credential"/> property's username
88-
/// should be the object ID of the identity; the password is ignored.
88+
/// should be the client ID of the identity; the password is ignored.
8989
/// For a system-assigned managed identity,
9090
/// the <see cref="SqlContext.Credential"/> property
9191
/// should be <see langword="null"/>.
@@ -148,4 +148,18 @@ public enum AzureAuthenticationMode // ~> M.D.S.SqlAuthenticationMethod
148148
/// </list>
149149
/// </remarks>
150150
AadDefault = 9, // ActiveDirectoryDefault
151+
152+
/// <summary>
153+
/// Entra ID workload identity authentication mode.
154+
/// </summary>
155+
/// <remarks>
156+
/// This mode is similar to managed identity authentication, except that
157+
/// default values are taken from environment variables. If the
158+
/// <see cref="SqlContext.Credential"/> property is not
159+
/// <see langword="null"/>, the credential's username overrides any
160+
/// client ID found in the environment, and the credential's password is
161+
/// ignored.
162+
/// </remarks>
163+
/// <see href="https://learn.microsoft.com/en-ca/sql/connect/ado-net/sql/azure-active-directory-authentication#using-workload-identity-authentication"/>
164+
AadWorkloadIdentity = 10, // ActiveDirectoryWorkloadIdentity
151165
}

PSql/Data/AzureSqlContext.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,7 @@ private protected override void
233233
// Optional, password ignored
234234
case AadManagedIdentity:
235235
case AadDefault:
236+
case AadWorkloadIdentity:
236237
if (!Credential.IsNullOrEmpty())
237238
builder.AppendUserName(Credential.UserName);
238239
break;

PSql/Utilities/AzureAuthenticationModeExtensions.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ internal static class AzureAuthenticationModeExtensions
1919
AadDeviceCodeFlow => "Active Directory Device Code Flow",
2020
AadManagedIdentity => "Active Directory Managed Identity",
2121
AadDefault => "Active Directory Default",
22+
AadWorkloadIdentity => "Active Directory Workload Identity",
2223
_ => null,
2324
};
2425
}

PSql/Utilities/SqlClientVersionExtensions.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ public static bool SupportsAuthenticationMode(
8383
AadDeviceCodeFlow => version >= Mds2_1,
8484
AadManagedIdentity => version >= Mds2_1,
8585
AadDefault => version >= Mds3,
86+
AadWorkloadIdentity => version >= Mds5_2,
8687
_ => false,
8788
};
8889

PSql/en-US/PSql.dll-help.xml

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -937,7 +937,7 @@
937937
<dev:value>AadManagedIdentity</dev:value>
938938
<maml:description>
939939
<maml:para>
940-
Entra ID managed identity authentication mode. For a user-assigned identity, -Credential is required and should match the object ID of the identity; the password is ignored. For a system-assigned identity, -Credential should be omitted.
940+
Entra ID managed identity authentication mode. For a user-assigned identity, -Credential is required and should match the client ID of the identity; the password is ignored. For a system-assigned identity, -Credential should be omitted.
941941
</maml:para>
942942
</maml:description>
943943
</dev:possibleValue>
@@ -949,6 +949,14 @@
949949
</maml:para>
950950
</maml:description>
951951
</dev:possibleValue>
952+
<dev:possibleValue>
953+
<dev:value>AadWorkloadIdentity</dev:value>
954+
<maml:description>
955+
<maml:para>
956+
Entra ID workload identity authentication mode. This mode is similar to managed identity authentication, except that default values are taken from environment variables. If a -Credential is provided, its username overrides any client ID found in the environment, and its password is ignored.
957+
</maml:para>
958+
</maml:description>
959+
</dev:possibleValue>
952960
</dev:possibleValues>
953961
</command:parameter>
954962

0 commit comments

Comments
 (0)