diff --git a/doc/snippets/Microsoft.Data.SqlClient/SqlAuthenticationMethod.xml b/doc/snippets/Microsoft.Data.SqlClient/SqlAuthenticationMethod.xml
index a52a2ec41a..91f6c6b1a5 100644
--- a/doc/snippets/Microsoft.Data.SqlClient/SqlAuthenticationMethod.xml
+++ b/doc/snippets/Microsoft.Data.SqlClient/SqlAuthenticationMethod.xml
@@ -45,5 +45,9 @@
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 Azure CLI credential. Use this mode to connect to a SQL Database using AzureCliCredential to acquire an access token. This method does not fallback to the "Active Directory Interactive" authentication method.
+ 10
+
diff --git a/src/Microsoft.Data.SqlClient/netcore/ref/Microsoft.Data.SqlClient.cs b/src/Microsoft.Data.SqlClient/netcore/ref/Microsoft.Data.SqlClient.cs
index 92cb042b76..dc1f80196a 100644
--- a/src/Microsoft.Data.SqlClient/netcore/ref/Microsoft.Data.SqlClient.cs
+++ b/src/Microsoft.Data.SqlClient/netcore/ref/Microsoft.Data.SqlClient.cs
@@ -176,6 +176,8 @@ public enum SqlAuthenticationMethod
ActiveDirectoryMSI = 8,
///
ActiveDirectoryDefault = 9,
+ ///
+ ActiveDirectoryAzureCli = 10,
///
NotSpecified = 0,
///
diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlAuthenticationProviderManager.NetCoreApp.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlAuthenticationProviderManager.NetCoreApp.cs
index 094114f357..7129b7941e 100644
--- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlAuthenticationProviderManager.NetCoreApp.cs
+++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlAuthenticationProviderManager.NetCoreApp.cs
@@ -153,6 +153,8 @@ private static SqlAuthenticationMethod AuthenticationEnumFromString(string authe
return SqlAuthenticationMethod.ActiveDirectoryMSI;
case ActiveDirectoryDefault:
return SqlAuthenticationMethod.ActiveDirectoryDefault;
+ case ActiveDirectoryAzureCli:
+ return SqlAuthenticationMethod.ActiveDirectoryAzureCli;
default:
throw SQL.UnsupportedAuthentication(authentication);
}
diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlAuthenticationProviderManager.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlAuthenticationProviderManager.cs
index 401fc23466..90a8a838da 100644
--- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlAuthenticationProviderManager.cs
+++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlAuthenticationProviderManager.cs
@@ -20,6 +20,7 @@ internal partial class SqlAuthenticationProviderManager
private const string ActiveDirectoryManagedIdentity = "active directory managed identity";
private const string ActiveDirectoryMSI = "active directory msi";
private const string ActiveDirectoryDefault = "active directory default";
+ private const string ActiveDirectoryAzureCli = "active directory azure cli";
private readonly IReadOnlyCollection _authenticationsWithAppSpecifiedProvider;
private readonly ConcurrentDictionary _providers;
@@ -45,6 +46,7 @@ private static void SetDefaultAuthProviders(SqlAuthenticationProviderManager ins
instance.SetProvider(SqlAuthenticationMethod.ActiveDirectoryManagedIdentity, activeDirectoryAuthProvider);
instance.SetProvider(SqlAuthenticationMethod.ActiveDirectoryMSI, activeDirectoryAuthProvider);
instance.SetProvider(SqlAuthenticationMethod.ActiveDirectoryDefault, activeDirectoryAuthProvider);
+ instance.SetProvider(SqlAuthenticationMethod.ActiveDirectoryAzureCli, activeDirectoryAuthProvider);
}
}
///
diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlConnection.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlConnection.cs
index e314171b23..bf4cc0c881 100644
--- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlConnection.cs
+++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlConnection.cs
@@ -202,6 +202,10 @@ public SqlConnection(string connectionString, SqlCredential credential) : this()
{
throw SQL.SettingCredentialWithNonInteractiveArgument(DbConnectionStringBuilderUtil.ActiveDirectoryDefaultString);
}
+ else if (UsesActiveDirectoryAzureCli(connectionOptions))
+ {
+ throw SQL.SettingCredentialWithNonInteractiveArgument(DbConnectionStringBuilderUtil.ActiveDirectoryAzureCliString);
+ }
Credential = credential;
}
@@ -530,6 +534,11 @@ private bool UsesActiveDirectoryDefault(SqlConnectionString opt)
return opt != null && opt.Authentication == SqlAuthenticationMethod.ActiveDirectoryDefault;
}
+ private bool UsesActiveDirectoryAzureCli(SqlConnectionString opt)
+ {
+ return opt != null && opt.Authentication == SqlAuthenticationMethod.ActiveDirectoryAzureCli;
+ }
+
private bool UsesAuthentication(SqlConnectionString opt)
{
return opt != null && opt.Authentication != SqlAuthenticationMethod.NotSpecified;
@@ -619,6 +628,10 @@ public override string ConnectionString
{
throw SQL.SettingNonInteractiveWithCredential(DbConnectionStringBuilderUtil.ActiveDirectoryDefaultString);
}
+ else if (UsesActiveDirectoryAzureCli(connectionOptions))
+ {
+ throw SQL.SettingNonInteractiveWithCredential(DbConnectionStringBuilderUtil.ActiveDirectoryAzureCliString);
+ }
CheckAndThrowOnInvalidCombinationOfConnectionStringAndSqlCredential(connectionOptions);
}
@@ -999,6 +1012,10 @@ public SqlCredential Credential
{
throw SQL.SettingCredentialWithNonInteractiveInvalid(DbConnectionStringBuilderUtil.ActiveDirectoryDefaultString);
}
+ else if (UsesActiveDirectoryAzureCli(connectionOptions))
+ {
+ throw SQL.SettingCredentialWithNonInteractiveInvalid(DbConnectionStringBuilderUtil.ActiveDirectoryAzureCliString);
+ }
CheckAndThrowOnInvalidCombinationOfConnectionStringAndSqlCredential(connectionOptions);
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 6a0ee2e0e0..f4e7e479cd 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
@@ -1330,6 +1330,7 @@ private void Login(ServerInfo server, TimeoutTimer timeout, string newPassword,
|| ConnectionOptions.Authentication == SqlAuthenticationMethod.ActiveDirectoryManagedIdentity
|| ConnectionOptions.Authentication == SqlAuthenticationMethod.ActiveDirectoryMSI
|| ConnectionOptions.Authentication == SqlAuthenticationMethod.ActiveDirectoryDefault
+ || ConnectionOptions.Authentication == SqlAuthenticationMethod.ActiveDirectoryAzureCli
// Since AD Integrated may be acting like Windows integrated, additionally check _fedAuthRequired
|| (ConnectionOptions.Authentication == SqlAuthenticationMethod.ActiveDirectoryIntegrated && _fedAuthRequired)
|| _accessTokenCallback != null)
@@ -2159,6 +2160,7 @@ internal void OnFedAuthInfo(SqlFedAuthInfo fedAuthInfo)
|| ConnectionOptions.Authentication == SqlAuthenticationMethod.ActiveDirectoryManagedIdentity
|| ConnectionOptions.Authentication == SqlAuthenticationMethod.ActiveDirectoryMSI
|| ConnectionOptions.Authentication == SqlAuthenticationMethod.ActiveDirectoryDefault
+ || ConnectionOptions.Authentication == SqlAuthenticationMethod.ActiveDirectoryAzureCli
|| (ConnectionOptions.Authentication == SqlAuthenticationMethod.ActiveDirectoryIntegrated && _fedAuthRequired),
"Credentials aren't provided for calling MSAL");
Debug.Assert(fedAuthInfo != null, "info should not be null.");
@@ -2406,6 +2408,7 @@ internal SqlFedAuthToken GetFedAuthToken(SqlFedAuthInfo fedAuthInfo)
case SqlAuthenticationMethod.ActiveDirectoryManagedIdentity:
case SqlAuthenticationMethod.ActiveDirectoryMSI:
case SqlAuthenticationMethod.ActiveDirectoryDefault:
+ case SqlAuthenticationMethod.ActiveDirectoryAzureCli:
if (_activeDirectoryAuthTimeoutRetryHelper.State == ActiveDirectoryAuthenticationTimeoutRetryState.Retrying)
{
_fedAuthToken = _activeDirectoryAuthTimeoutRetryHelper.CachedToken;
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 90084028b3..a6b4025a56 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
@@ -7944,6 +7944,7 @@ internal int WriteFedAuthFeatureRequest(FederatedAuthenticationFeatureExtensionD
workflow = TdsEnums.MSALWORKFLOW_ACTIVEDIRECTORYMANAGEDIDENTITY;
break;
case SqlAuthenticationMethod.ActiveDirectoryDefault:
+ case SqlAuthenticationMethod.ActiveDirectoryAzureCli:
workflow = TdsEnums.MSALWORKFLOW_ACTIVEDIRECTORYDEFAULT;
break;
default:
diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlAuthenticationProviderManager.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlAuthenticationProviderManager.cs
index d0757807be..e849a181ac 100644
--- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlAuthenticationProviderManager.cs
+++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlAuthenticationProviderManager.cs
@@ -22,6 +22,7 @@ internal class SqlAuthenticationProviderManager
private const string ActiveDirectoryManagedIdentity = "active directory managed identity";
private const string ActiveDirectoryMSI = "active directory msi";
private const string ActiveDirectoryDefault = "active directory default";
+ private const string ActiveDirectoryAzureCli = "active directory azure cli";
static SqlAuthenticationProviderManager()
{
@@ -52,6 +53,7 @@ static SqlAuthenticationProviderManager()
Instance.SetProvider(SqlAuthenticationMethod.ActiveDirectoryManagedIdentity, activeDirectoryAuthProvider);
Instance.SetProvider(SqlAuthenticationMethod.ActiveDirectoryMSI, activeDirectoryAuthProvider);
Instance.SetProvider(SqlAuthenticationMethod.ActiveDirectoryDefault, activeDirectoryAuthProvider);
+ Instance.SetProvider(SqlAuthenticationMethod.ActiveDirectoryAzureCli, activeDirectoryAuthProvider);
}
public static readonly SqlAuthenticationProviderManager Instance;
@@ -231,6 +233,8 @@ private static SqlAuthenticationMethod AuthenticationEnumFromString(string authe
return SqlAuthenticationMethod.ActiveDirectoryMSI;
case ActiveDirectoryDefault:
return SqlAuthenticationMethod.ActiveDirectoryDefault;
+ case ActiveDirectoryAzureCli:
+ return SqlAuthenticationMethod.ActiveDirectoryAzureCli;
default:
throw SQL.UnsupportedAuthentication(authentication);
}
diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlConnection.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlConnection.cs
index a329d626b0..b5d330aa75 100644
--- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlConnection.cs
+++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlConnection.cs
@@ -405,6 +405,11 @@ public SqlConnection(string connectionString, SqlCredential credential) : this()
throw SQL.SettingCredentialWithNonInteractiveArgument(DbConnectionStringBuilderUtil.ActiveDirectoryDefaultString);
}
+ if (UsesActiveDirectoryAzureCli(connectionOptions))
+ {
+ throw SQL.SettingCredentialWithNonInteractiveArgument(DbConnectionStringBuilderUtil.ActiveDirectoryAzureCliString);
+ }
+
Credential = credential;
}
// else
@@ -627,6 +632,11 @@ private bool UsesActiveDirectoryDefault(SqlConnectionString opt)
return opt != null && opt.Authentication == SqlAuthenticationMethod.ActiveDirectoryDefault;
}
+ private bool UsesActiveDirectoryAzureCli(SqlConnectionString opt)
+ {
+ return opt != null && opt.Authentication == SqlAuthenticationMethod.ActiveDirectoryAzureCli;
+ }
+
private bool UsesAuthentication(SqlConnectionString opt)
{
return opt != null && opt.Authentication != SqlAuthenticationMethod.NotSpecified;
@@ -834,6 +844,10 @@ override public string ConnectionString
{
throw SQL.SettingNonInteractiveWithCredential(DbConnectionStringBuilderUtil.ActiveDirectoryDefaultString);
}
+ else if (UsesActiveDirectoryAzureCli(connectionOptions))
+ {
+ throw SQL.SettingNonInteractiveWithCredential(DbConnectionStringBuilderUtil.ActiveDirectoryAzureCliString);
+ }
CheckAndThrowOnInvalidCombinationOfConnectionStringAndSqlCredential(connectionOptions);
}
@@ -1183,6 +1197,10 @@ public SqlCredential Credential
{
throw SQL.SettingCredentialWithNonInteractiveInvalid(DbConnectionStringBuilderUtil.ActiveDirectoryDefaultString);
}
+ else if (UsesActiveDirectoryAzureCli(connectionOptions))
+ {
+ throw SQL.SettingCredentialWithNonInteractiveInvalid(DbConnectionStringBuilderUtil.ActiveDirectoryAzureCliString);
+ }
CheckAndThrowOnInvalidCombinationOfConnectionStringAndSqlCredential(connectionOptions);
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 068b37dc71..499e432247 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
@@ -1595,6 +1595,7 @@ private void Login(ServerInfo server, TimeoutTimer timeout, string newPassword,
|| ConnectionOptions.Authentication == SqlAuthenticationMethod.ActiveDirectoryManagedIdentity
|| ConnectionOptions.Authentication == SqlAuthenticationMethod.ActiveDirectoryMSI
|| ConnectionOptions.Authentication == SqlAuthenticationMethod.ActiveDirectoryDefault
+ || ConnectionOptions.Authentication == SqlAuthenticationMethod.ActiveDirectoryAzureCli
// Since AD Integrated may be acting like Windows integrated, additionally check _fedAuthRequired
|| (ConnectionOptions.Authentication == SqlAuthenticationMethod.ActiveDirectoryIntegrated && _fedAuthRequired)
|| _accessTokenCallback != null)
@@ -1991,7 +1992,8 @@ private bool ShouldDisableTnir(SqlConnectionString connectionOptions)
connectionOptions.Authentication == SqlAuthenticationMethod.ActiveDirectoryDeviceCodeFlow ||
connectionOptions.Authentication == SqlAuthenticationMethod.ActiveDirectoryManagedIdentity ||
connectionOptions.Authentication == SqlAuthenticationMethod.ActiveDirectoryMSI ||
- connectionOptions.Authentication == SqlAuthenticationMethod.ActiveDirectoryDefault;
+ connectionOptions.Authentication == SqlAuthenticationMethod.ActiveDirectoryDefault ||
+ connectionOptions.Authentication == SqlAuthenticationMethod.ActiveDirectoryAzureCli;
// Check if the user had explicitly specified the TNIR option in the connection string or the connection string builder.
// If the user has specified the option in the connection string explicitly, then we shouldn't disable TNIR.
@@ -2585,6 +2587,7 @@ internal void OnFedAuthInfo(SqlFedAuthInfo fedAuthInfo)
|| ConnectionOptions.Authentication == SqlAuthenticationMethod.ActiveDirectoryManagedIdentity
|| ConnectionOptions.Authentication == SqlAuthenticationMethod.ActiveDirectoryMSI
|| ConnectionOptions.Authentication == SqlAuthenticationMethod.ActiveDirectoryDefault
+ || ConnectionOptions.Authentication == SqlAuthenticationMethod.ActiveDirectoryAzureCli
|| ConnectionOptions.Authentication == SqlAuthenticationMethod.ActiveDirectoryDeviceCodeFlow
|| (ConnectionOptions.Authentication == SqlAuthenticationMethod.ActiveDirectoryIntegrated && _fedAuthRequired),
"Credentials aren't provided for calling MSAL");
@@ -2819,6 +2822,7 @@ internal SqlFedAuthToken GetFedAuthToken(SqlFedAuthInfo fedAuthInfo)
case SqlAuthenticationMethod.ActiveDirectoryDeviceCodeFlow:
case SqlAuthenticationMethod.ActiveDirectoryManagedIdentity:
case SqlAuthenticationMethod.ActiveDirectoryMSI:
+ case SqlAuthenticationMethod.ActiveDirectoryAzureCli:
case SqlAuthenticationMethod.ActiveDirectoryDefault:
if (_activeDirectoryAuthTimeoutRetryHelper.State == ActiveDirectoryAuthenticationTimeoutRetryState.Retrying)
{
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 b06bb167da..a37b801861 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
@@ -594,6 +594,9 @@ internal void Connect(ServerInfo serverInfo,
case SqlAuthenticationMethod.ActiveDirectoryDefault:
SqlClientEventSource.Log.TryTraceEvent(" Active Directory Default authentication");
break;
+ case SqlAuthenticationMethod.ActiveDirectoryAzureCli:
+ SqlClientEventSource.Log.TryTraceEvent(" Active Directory Azure CLI authentication");
+ break;
case SqlAuthenticationMethod.SqlPassword:
SqlClientEventSource.Log.TryTraceEvent(" SQL Password authentication");
break;
@@ -8741,6 +8744,7 @@ internal int WriteFedAuthFeatureRequest(FederatedAuthenticationFeatureExtensionD
case SqlAuthenticationMethod.ActiveDirectoryMSI:
workflow = TdsEnums.MSALWORKFLOW_ACTIVEDIRECTORYMANAGEDIDENTITY;
break;
+ case SqlAuthenticationMethod.ActiveDirectoryAzureCli:
case SqlAuthenticationMethod.ActiveDirectoryDefault:
workflow = TdsEnums.MSALWORKFLOW_ACTIVEDIRECTORYDEFAULT;
break;
diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Common/DbConnectionStringCommon.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Common/DbConnectionStringCommon.cs
index 6bef73963b..705009ddfe 100644
--- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Common/DbConnectionStringCommon.cs
+++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Common/DbConnectionStringCommon.cs
@@ -347,6 +347,7 @@ internal static ApplicationIntent ConvertToApplicationIntent(string keyword, obj
internal const string ActiveDirectoryManagedIdentityString = "Active Directory Managed Identity";
internal const string ActiveDirectoryMSIString = "Active Directory MSI";
internal const string ActiveDirectoryDefaultString = "Active Directory Default";
+ internal const string ActiveDirectoryAzureCliString = "Active Directory Azure CLI";
const string SqlCertificateString = "Sql Certificate";
#if DEBUG
@@ -361,7 +362,8 @@ internal static ApplicationIntent ConvertToApplicationIntent(string keyword, obj
"ActiveDirectoryDeviceCodeFlow",
"ActiveDirectoryManagedIdentity",
"ActiveDirectoryMSI",
- "ActiveDirectoryDefault"
+ "ActiveDirectoryDefault",
+ "ActiveDirectoryAzureCli"
};
private static bool IsValidAuthenticationMethodEnum()
@@ -444,6 +446,12 @@ internal static bool TryConvertToAuthenticationType(string value, out SqlAuthent
result = SqlAuthenticationMethod.ActiveDirectoryDefault;
isSuccess = true;
}
+ else if (StringComparer.InvariantCultureIgnoreCase.Equals(value, ActiveDirectoryAzureCliString)
+ || StringComparer.InvariantCultureIgnoreCase.Equals(value, Convert.ToString(SqlAuthenticationMethod.ActiveDirectoryAzureCli, CultureInfo.InvariantCulture)))
+ {
+ result = SqlAuthenticationMethod.ActiveDirectoryAzureCli;
+ isSuccess = true;
+ }
#if ADONET_CERT_AUTH && NETFRAMEWORK
else if (StringComparer.InvariantCultureIgnoreCase.Equals(value, SqlCertificateString)
|| StringComparer.InvariantCultureIgnoreCase.Equals(value, Convert.ToString(SqlAuthenticationMethod.SqlCertificate, CultureInfo.InvariantCulture))) {
@@ -516,7 +524,7 @@ internal static string ColumnEncryptionSettingToString(SqlConnectionColumnEncryp
internal static bool IsValidAuthenticationTypeValue(SqlAuthenticationMethod value)
{
- Debug.Assert(Enum.GetNames(typeof(SqlAuthenticationMethod)).Length == 10, "SqlAuthenticationMethod enum has changed, update needed");
+ Debug.Assert(Enum.GetNames(typeof(SqlAuthenticationMethod)).Length == 11, "SqlAuthenticationMethod enum has changed, update needed");
return value == SqlAuthenticationMethod.SqlPassword
|| value == SqlAuthenticationMethod.ActiveDirectoryPassword
|| value == SqlAuthenticationMethod.ActiveDirectoryIntegrated
@@ -526,6 +534,7 @@ internal static bool IsValidAuthenticationTypeValue(SqlAuthenticationMethod valu
|| value == SqlAuthenticationMethod.ActiveDirectoryManagedIdentity
|| value == SqlAuthenticationMethod.ActiveDirectoryMSI
|| value == SqlAuthenticationMethod.ActiveDirectoryDefault
+ || value == SqlAuthenticationMethod.ActiveDirectoryAzureCli
#if ADONET_CERT_AUTH && NETFRAMEWORK
|| value == SqlAuthenticationMethod.SqlCertificate
#endif
@@ -547,6 +556,7 @@ internal static string AuthenticationTypeToString(SqlAuthenticationMethod value)
SqlAuthenticationMethod.ActiveDirectoryManagedIdentity => ActiveDirectoryManagedIdentityString,
SqlAuthenticationMethod.ActiveDirectoryMSI => ActiveDirectoryMSIString,
SqlAuthenticationMethod.ActiveDirectoryDefault => ActiveDirectoryDefaultString,
+ SqlAuthenticationMethod.ActiveDirectoryAzureCli => ActiveDirectoryAzureCliString,
#if ADONET_CERT_AUTH && NETFRAMEWORK
SqlAuthenticationMethod.SqlCertificate => SqlCertificateString,
#endif
diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/ActiveDirectoryAuthenticationProvider.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/ActiveDirectoryAuthenticationProvider.cs
index 60151f1be1..088a8c93a1 100644
--- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/ActiveDirectoryAuthenticationProvider.cs
+++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/ActiveDirectoryAuthenticationProvider.cs
@@ -84,7 +84,8 @@ public override bool IsSupported(SqlAuthenticationMethod authentication)
|| authentication == SqlAuthenticationMethod.ActiveDirectoryDeviceCodeFlow
|| authentication == SqlAuthenticationMethod.ActiveDirectoryManagedIdentity
|| authentication == SqlAuthenticationMethod.ActiveDirectoryMSI
- || authentication == SqlAuthenticationMethod.ActiveDirectoryDefault;
+ || authentication == SqlAuthenticationMethod.ActiveDirectoryDefault
+ || authentication == SqlAuthenticationMethod.ActiveDirectoryAzureCli;
}
///
@@ -167,6 +168,17 @@ public override async Task AcquireTokenAsync(SqlAuthenti
SqlClientEventSource.Log.TryTraceEvent("AcquireTokenAsync | Acquired access token for Default auth mode. Expiry Time: {0}", accessToken.ExpiresOn);
return new SqlAuthenticationToken(accessToken.Token, accessToken.ExpiresOn);
}
+ if (parameters.AuthenticationMethod == SqlAuthenticationMethod.ActiveDirectoryAzureCli)
+ {
+ AzureCliCredentialOptions azureCliCredentialOptions = new()
+ {
+ AuthorityHost = new Uri(authority),
+ };
+
+ AccessToken accessToken = await new AzureCliCredential(azureCliCredentialOptions).GetTokenAsync(tokenRequestContext, cts.Token).ConfigureAwait(false);
+ SqlClientEventSource.Log.TryTraceEvent("AcquireTokenAsync | Acquired access token for Azure CLI auth mode. Expiry Time: {0}", accessToken.ExpiresOn);
+ return new SqlAuthenticationToken(accessToken.Token, accessToken.ExpiresOn);
+ }
TokenCredentialOptions tokenCredentialOptions = new TokenCredentialOptions() { AuthorityHost = new Uri(authority) };
diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlConnectionString.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlConnectionString.cs
index 65d8dcc9cf..814c7a2972 100644
--- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlConnectionString.cs
+++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlConnectionString.cs
@@ -626,6 +626,10 @@ internal SqlConnectionString(string connectionString) : base(connectionString, G
{
throw SQL.NonInteractiveWithPassword(DbConnectionStringBuilderUtil.ActiveDirectoryDefaultString);
}
+ if (Authentication == SqlAuthenticationMethod.ActiveDirectoryAzureCli && _hasPasswordKeyword)
+ {
+ throw SQL.NonInteractiveWithPassword(DbConnectionStringBuilderUtil.ActiveDirectoryAzureCliString);
+ }
#if ADONET_CERT_AUTH && NETFRAMEWORK
if (!DbConnectionStringBuilderUtil.IsValidCertificateValue(_certificate))
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 2e727be277..d39d6d32e5 100644
--- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/TdsEnums.cs
+++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/TdsEnums.cs
@@ -1212,6 +1212,8 @@ public enum SqlAuthenticationMethod
///
ActiveDirectoryDefault,
+ ///
+ ActiveDirectoryAzureCli,
#if ADONET_CERT_AUTH && NETFRAMEWORK
SqlCertificate
#endif
diff --git a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlConnectionStringBuilderTest.cs b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlConnectionStringBuilderTest.cs
index b3a090f58f..f1a8f3168b 100644
--- a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlConnectionStringBuilderTest.cs
+++ b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlConnectionStringBuilderTest.cs
@@ -38,6 +38,7 @@ public partial class SqlConnectionStringBuilderTest
[InlineData("Authentication = Active Directory MSI ")]
[InlineData("Authentication = ActiveDirectoryMSI ")]
[InlineData("Authentication = Active Directory Default ")]
+ [InlineData("Authentication = Active Directory Azure CLI ")]
[InlineData("Authentication = ActiveDirectoryDefault ")]
[InlineData("Command Timeout = 5")]
[InlineData("Command Timeout = 15")]
diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectivityTests/AADConnectionTest.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectivityTests/AADConnectionTest.cs
index 06080a9ca6..a388511c5f 100644
--- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectivityTests/AADConnectionTest.cs
+++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectivityTests/AADConnectionTest.cs
@@ -576,6 +576,64 @@ public static void ActiveDirectoryDefaultWithAccessTokenCallbackMustFail()
Assert.Contains(expectedMessage, e.Message);
}
+ [ConditionalFact(nameof(IsAADConnStringsSetup))]
+ public static void ActiveDirectoryAzureCliWithCredentialsMustFail()
+ {
+ // connection fails with expected error message.
+ string[] credKeys = { "Authentication", "User ID", "Password", "UID", "PWD" };
+ string connStrWithNoCred = DataTestUtility.RemoveKeysInConnStr(DataTestUtility.AADPasswordConnectionString, credKeys) +
+ "Authentication=Active Directory Azure CLI;";
+
+ SecureString str = new SecureString();
+ foreach (char c in "hello")
+ {
+ str.AppendChar(c);
+ }
+ str.MakeReadOnly();
+ SqlCredential credential = new SqlCredential("someuser", str);
+ InvalidOperationException e = Assert.Throws(() => ConnectAndDisconnect(connStrWithNoCred, credential));
+
+ string expectedMessage = "Cannot set the Credential property if 'Authentication=Active Directory Azure CLI' has been specified in the connection string.";
+ Assert.Contains(expectedMessage, e.Message);
+ }
+
+ [ConditionalFact(nameof(IsAADConnStringsSetup))]
+ public static void ActiveDirectoryAzureCliWithPasswordMustFail()
+ {
+ // connection fails with expected error message.
+ string[] credKeys = { "Authentication", "User ID", "Password", "UID", "PWD" };
+ string connStrWithNoCred = DataTestUtility.RemoveKeysInConnStr(DataTestUtility.AADPasswordConnectionString, credKeys) +
+ "Authentication=ActiveDirectoryAzureCLI; Password=anything";
+
+ ArgumentException e = Assert.Throws(() => ConnectAndDisconnect(connStrWithNoCred));
+
+ string expectedMessage = "Cannot use 'Authentication=Active Directory Azure CLI' with 'Password' or 'PWD' connection string keywords.";
+ Assert.Contains(expectedMessage, e.Message);
+ }
+
+ [ConditionalFact(nameof(IsAADConnStringsSetup))]
+ public static void ActiveDirectoryAzureCliWithAccessTokenCallbackMustFail()
+ {
+ // connection fails with expected error message.
+ string[] credKeys = { "Authentication", "User ID", "Password", "UID", "PWD" };
+ string connStrWithNoCred = DataTestUtility.RemoveKeysInConnStr(DataTestUtility.AADPasswordConnectionString, credKeys) +
+ "Authentication=ActiveDirectoryAzureCLI";
+ InvalidOperationException e = Assert.Throws(() =>
+ {
+ using (SqlConnection conn = new SqlConnection(connStrWithNoCred))
+ {
+ conn.AccessTokenCallback = (ctx, token) =>
+ Task.FromResult(new SqlAuthenticationToken("my token", DateTimeOffset.MaxValue));
+ conn.Open();
+
+ Assert.NotEqual(System.Data.ConnectionState.Open, conn.State);
+ }
+ });
+
+ string expectedMessage = "Cannot set the AccessTokenCallback property if 'Authentication=Active Directory Default' has been specified in the connection string.";
+ Assert.Contains(expectedMessage, e.Message);
+ }
+
[ConditionalFact(nameof(IsAADConnStringsSetup))]
public static void AccessTokenCallbackMustOpenPassAndChangePropertyFail()
{