Skip to content

Commit

Permalink
Feature | Introduce "Active Directory Default" authentication mode
Browse files Browse the repository at this point in the history
  • Loading branch information
cheenamalhotra committed Apr 20, 2021
1 parent 1d4522a commit 6a390fe
Show file tree
Hide file tree
Showing 38 changed files with 276 additions and 92 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -41,5 +41,9 @@
<summary>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.</summary>
<value>8</value>
</ActiveDirectoryMSI>
<ActiveDirectoryDefault>
<summary>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 access token. This method does not fallback to "Active Directory Interactive" authentication method.</summary>
<value>9</value>
</ActiveDirectoryDefault>
</members>
</docs>
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,8 @@ public enum SqlAuthenticationMethod
ActiveDirectoryManagedIdentity = 7,
/// <include file='../../../../doc/snippets/Microsoft.Data.SqlClient/SqlAuthenticationMethod.xml' path='docs/members[@name="SqlAuthenticationMethod"]/ActiveDirectoryMSI/*'/>
ActiveDirectoryMSI = 8,
/// <include file='../../../../doc/snippets/Microsoft.Data.SqlClient/SqlAuthenticationMethod.xml' path='docs/members[@name="SqlAuthenticationMethod"]/ActiveDirectoryDefault/*'/>
ActiveDirectoryDefault = 9,
/// <include file='../../../../doc/snippets/Microsoft.Data.SqlClient/SqlAuthenticationMethod.xml' path='docs/members[@name="SqlAuthenticationMethod"]/NotSpecified/*'/>
NotSpecified = 0,
/// <include file='../../../../doc/snippets/Microsoft.Data.SqlClient/SqlAuthenticationMethod.xml' path='docs/members[@name="SqlAuthenticationMethod"]/SqlPassword/*'/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,10 +106,11 @@ internal static string ConvertToString(object value)
const string ActiveDirectoryDeviceCodeFlowString = "Active Directory Device Code Flow";
internal const string ActiveDirectoryManagedIdentityString = "Active Directory Managed Identity";
internal const string ActiveDirectoryMSIString = "Active Directory MSI";
internal const string ActiveDirectoryDefaultString = "Active Directory Default";

internal static bool TryConvertToAuthenticationType(string value, out SqlAuthenticationMethod result)
{
Debug.Assert(Enum.GetNames(typeof(SqlAuthenticationMethod)).Length == 9, "SqlAuthenticationMethod enum has changed, update needed");
Debug.Assert(Enum.GetNames(typeof(SqlAuthenticationMethod)).Length == 10, "SqlAuthenticationMethod enum has changed, update needed");

bool isSuccess = false;

Expand Down Expand Up @@ -161,6 +162,12 @@ internal static bool TryConvertToAuthenticationType(string value, out SqlAuthent
result = SqlAuthenticationMethod.ActiveDirectoryMSI;
isSuccess = true;
}
else if (StringComparer.InvariantCultureIgnoreCase.Equals(value, ActiveDirectoryDefaultString)
|| StringComparer.InvariantCultureIgnoreCase.Equals(value, Convert.ToString(SqlAuthenticationMethod.ActiveDirectoryDefault, CultureInfo.InvariantCulture)))
{
result = SqlAuthenticationMethod.ActiveDirectoryDefault;
isSuccess = true;
}
else
{
result = DbConnectionStringDefaults.Authentication;
Expand Down Expand Up @@ -510,6 +517,7 @@ internal static bool IsValidAuthenticationTypeValue(SqlAuthenticationMethod valu
|| value == SqlAuthenticationMethod.ActiveDirectoryDeviceCodeFlow
|| value == SqlAuthenticationMethod.ActiveDirectoryManagedIdentity
|| value == SqlAuthenticationMethod.ActiveDirectoryMSI
|| value == SqlAuthenticationMethod.ActiveDirectoryDefault
|| value == SqlAuthenticationMethod.NotSpecified;
}

Expand All @@ -535,6 +543,8 @@ internal static string AuthenticationTypeToString(SqlAuthenticationMethod value)
return ActiveDirectoryManagedIdentityString;
case SqlAuthenticationMethod.ActiveDirectoryMSI:
return ActiveDirectoryMSIString;
case SqlAuthenticationMethod.ActiveDirectoryDefault:
return ActiveDirectoryDefaultString;
default:
return null;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,8 @@ private static SqlAuthenticationMethod AuthenticationEnumFromString(string authe
return SqlAuthenticationMethod.ActiveDirectoryManagedIdentity;
case ActiveDirectoryMSI:
return SqlAuthenticationMethod.ActiveDirectoryMSI;
case ActiveDirectoryDefault:
return SqlAuthenticationMethod.ActiveDirectoryDefault;
default:
throw SQL.UnsupportedAuthentication(authentication);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ internal partial class SqlAuthenticationProviderManager
private const string ActiveDirectoryDeviceCodeFlow = "active directory device code flow";
private const string ActiveDirectoryManagedIdentity = "active directory managed identity";
private const string ActiveDirectoryMSI = "active directory msi";
private const string ActiveDirectoryDefault = "active directory default";

private readonly string _typeName;
private readonly IReadOnlyCollection<SqlAuthenticationMethod> _authenticationsWithAppSpecifiedProvider;
Expand All @@ -46,6 +47,7 @@ private static void SetDefaultAuthProviders(SqlAuthenticationProviderManager ins
instance.SetProvider(SqlAuthenticationMethod.ActiveDirectoryDeviceCodeFlow, activeDirectoryAuthProvider);
instance.SetProvider(SqlAuthenticationMethod.ActiveDirectoryManagedIdentity, activeDirectoryAuthProvider);
instance.SetProvider(SqlAuthenticationMethod.ActiveDirectoryMSI, activeDirectoryAuthProvider);
instance.SetProvider(SqlAuthenticationMethod.ActiveDirectoryDefault, activeDirectoryAuthProvider);
}
}
/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -184,11 +184,15 @@ public SqlConnection(string connectionString, SqlCredential credential) : this()
}
else if (UsesActiveDirectoryManagedIdentity(connectionOptions))
{
throw SQL.SettingCredentialWithManagedIdentityArgument(DbConnectionStringBuilderUtil.ActiveDirectoryManagedIdentityString);
throw SQL.SettingCredentialWithNonInteractiveArgument(DbConnectionStringBuilderUtil.ActiveDirectoryManagedIdentityString);
}
else if (UsesActiveDirectoryMSI(connectionOptions))
{
throw SQL.SettingCredentialWithManagedIdentityArgument(DbConnectionStringBuilderUtil.ActiveDirectoryMSIString);
throw SQL.SettingCredentialWithNonInteractiveArgument(DbConnectionStringBuilderUtil.ActiveDirectoryMSIString);
}
else if (UsesActiveDirectoryDefault(connectionOptions))
{
throw SQL.SettingCredentialWithNonInteractiveArgument(DbConnectionStringBuilderUtil.ActiveDirectoryDefaultString);
}

Credential = credential;
Expand Down Expand Up @@ -463,6 +467,11 @@ private bool UsesActiveDirectoryMSI(SqlConnectionString opt)
return opt != null && opt.Authentication == SqlAuthenticationMethod.ActiveDirectoryMSI;
}

private bool UsesActiveDirectoryDefault(SqlConnectionString opt)
{
return opt != null && opt.Authentication == SqlAuthenticationMethod.ActiveDirectoryDefault;
}

private bool UsesAuthentication(SqlConnectionString opt)
{
return opt != null && opt.Authentication != SqlAuthenticationMethod.NotSpecified;
Expand Down Expand Up @@ -520,7 +529,7 @@ public override string ConnectionString
if (_credential != null)
{
// Check for Credential being used with Authentication=ActiveDirectoryIntegrated | ActiveDirectoryInteractive |
// ActiveDirectoryDeviceCodeFlow | ActiveDirectoryManagedIdentity/ActiveDirectoryMSI. Since a different error string is used
// ActiveDirectoryDeviceCodeFlow | ActiveDirectoryManagedIdentity/ActiveDirectoryMSI | ActiveDirectoryDefault. Since a different error string is used
// for this case in ConnectionString setter vs in Credential setter, check for this error case before calling
// CheckAndThrowOnInvalidCombinationOfConnectionStringAndSqlCredential, which is common to both setters.
if (UsesActiveDirectoryIntegrated(connectionOptions))
Expand All @@ -537,11 +546,15 @@ public override string ConnectionString
}
else if (UsesActiveDirectoryManagedIdentity(connectionOptions))
{
throw SQL.SettingManagedIdentityWithCredential(DbConnectionStringBuilderUtil.ActiveDirectoryManagedIdentityString);
throw SQL.SettingNonInteractiveWithCredential(DbConnectionStringBuilderUtil.ActiveDirectoryManagedIdentityString);
}
else if (UsesActiveDirectoryMSI(connectionOptions))
{
throw SQL.SettingManagedIdentityWithCredential(DbConnectionStringBuilderUtil.ActiveDirectoryMSIString);
throw SQL.SettingNonInteractiveWithCredential(DbConnectionStringBuilderUtil.ActiveDirectoryMSIString);
}
else if (UsesActiveDirectoryDefault(connectionOptions))
{
throw SQL.SettingNonInteractiveWithCredential(DbConnectionStringBuilderUtil.ActiveDirectoryDefaultString);
}

CheckAndThrowOnInvalidCombinationOfConnectionStringAndSqlCredential(connectionOptions);
Expand Down Expand Up @@ -833,7 +846,7 @@ public SqlCredential Credential
{
var connectionOptions = (SqlConnectionString)ConnectionOptions;
// Check for Credential being used with Authentication=ActiveDirectoryIntegrated | ActiveDirectoryInteractive |
// ActiveDirectoryDeviceCodeFlow | ActiveDirectoryManagedIdentity/ActiveDirectoryMSI. Since a different error string is used
// ActiveDirectoryDeviceCodeFlow | ActiveDirectoryManagedIdentity/ActiveDirectoryMSI | ActiveDirectoryDefault. Since a different error string is used
// for this case in ConnectionString setter vs in Credential setter, check for this error case before calling
// CheckAndThrowOnInvalidCombinationOfConnectionStringAndSqlCredential, which is common to both setters.
if (UsesActiveDirectoryIntegrated(connectionOptions))
Expand All @@ -850,11 +863,15 @@ public SqlCredential Credential
}
else if (UsesActiveDirectoryManagedIdentity(connectionOptions))
{
throw SQL.SettingCredentialWithManagedIdentityInvalid(DbConnectionStringBuilderUtil.ActiveDirectoryManagedIdentityString);
throw SQL.SettingCredentialWithNonInteractiveInvalid(DbConnectionStringBuilderUtil.ActiveDirectoryManagedIdentityString);
}
else if (UsesActiveDirectoryMSI(connectionOptions))
{
throw SQL.SettingCredentialWithManagedIdentityInvalid(DbConnectionStringBuilderUtil.ActiveDirectoryMSIString);
throw SQL.SettingCredentialWithNonInteractiveInvalid(DbConnectionStringBuilderUtil.ActiveDirectoryMSIString);
}
else if (UsesActiveDirectoryDefault(connectionOptions))
{
throw SQL.SettingCredentialWithNonInteractiveInvalid(DbConnectionStringBuilderUtil.ActiveDirectoryDefaultString);
}

CheckAndThrowOnInvalidCombinationOfConnectionStringAndSqlCredential(connectionOptions);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -478,12 +478,17 @@ internal SqlConnectionString(string connectionString) : base(connectionString, G

if (Authentication == SqlAuthenticationMethod.ActiveDirectoryManagedIdentity && HasPasswordKeyword)
{
throw SQL.ManagedIdentityWithPassword(DbConnectionStringBuilderUtil.ActiveDirectoryManagedIdentityString);
throw SQL.NonInteractiveWithPassword(DbConnectionStringBuilderUtil.ActiveDirectoryManagedIdentityString);
}

if (Authentication == SqlAuthenticationMethod.ActiveDirectoryMSI && HasPasswordKeyword)
{
throw SQL.ManagedIdentityWithPassword(DbConnectionStringBuilderUtil.ActiveDirectoryMSIString);
throw SQL.NonInteractiveWithPassword(DbConnectionStringBuilderUtil.ActiveDirectoryMSIString);
}

if (Authentication == SqlAuthenticationMethod.ActiveDirectoryDefault && HasPasswordKeyword)
{
throw SQL.NonInteractiveWithPassword(DbConnectionStringBuilderUtil.ActiveDirectoryDefaultString);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1308,6 +1308,7 @@ private void Login(ServerInfo server, TimeoutTimer timeout, string newPassword,
|| ConnectionOptions.Authentication == SqlAuthenticationMethod.ActiveDirectoryServicePrincipal
|| ConnectionOptions.Authentication == SqlAuthenticationMethod.ActiveDirectoryManagedIdentity
|| ConnectionOptions.Authentication == SqlAuthenticationMethod.ActiveDirectoryMSI
|| ConnectionOptions.Authentication == SqlAuthenticationMethod.ActiveDirectoryDefault
// Since AD Integrated may be acting like Windows integrated, additionally check _fedAuthRequired
|| (ConnectionOptions.Authentication == SqlAuthenticationMethod.ActiveDirectoryIntegrated && _fedAuthRequired))
{
Expand Down Expand Up @@ -2116,6 +2117,7 @@ internal void OnFedAuthInfo(SqlFedAuthInfo fedAuthInfo)
|| ConnectionOptions.Authentication == SqlAuthenticationMethod.ActiveDirectoryDeviceCodeFlow
|| ConnectionOptions.Authentication == SqlAuthenticationMethod.ActiveDirectoryManagedIdentity
|| ConnectionOptions.Authentication == SqlAuthenticationMethod.ActiveDirectoryMSI
|| ConnectionOptions.Authentication == SqlAuthenticationMethod.ActiveDirectoryDefault
|| (ConnectionOptions.Authentication == SqlAuthenticationMethod.ActiveDirectoryIntegrated && _fedAuthRequired),
"Credentials aren't provided for calling MSAL");
Debug.Assert(fedAuthInfo != null, "info should not be null.");
Expand Down Expand Up @@ -2358,6 +2360,7 @@ internal SqlFedAuthToken GetFedAuthToken(SqlFedAuthInfo fedAuthInfo)
case SqlAuthenticationMethod.ActiveDirectoryDeviceCodeFlow:
case SqlAuthenticationMethod.ActiveDirectoryManagedIdentity:
case SqlAuthenticationMethod.ActiveDirectoryMSI:
case SqlAuthenticationMethod.ActiveDirectoryDefault:
if (_activeDirectoryAuthTimeoutRetryHelper.State == ActiveDirectoryAuthenticationTimeoutRetryState.Retrying)
{
_fedAuthToken = _activeDirectoryAuthTimeoutRetryHelper.CachedToken;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -283,9 +283,9 @@ internal static Exception DeviceFlowWithUsernamePassword()
{
return ADP.Argument(System.StringsHelper.GetString(Strings.SQL_DeviceFlowWithUsernamePassword));
}
internal static Exception ManagedIdentityWithPassword(string authenticationMode)
internal static Exception NonInteractiveWithPassword(string authenticationMode)
{
return ADP.Argument(System.StringsHelper.GetString(Strings.SQL_ManagedIdentityWithPassword, authenticationMode));
return ADP.Argument(System.StringsHelper.GetString(Strings.SQL_NonInteractiveWithPassword, authenticationMode));
}
static internal Exception SettingIntegratedWithCredential()
{
Expand All @@ -299,9 +299,9 @@ static internal Exception SettingDeviceFlowWithCredential()
{
return ADP.InvalidOperation(System.StringsHelper.GetString(Strings.SQL_SettingDeviceFlowWithCredential));
}
static internal Exception SettingManagedIdentityWithCredential(string authenticationMode)
static internal Exception SettingNonInteractiveWithCredential(string authenticationMode)
{
return ADP.InvalidOperation(System.StringsHelper.GetString(Strings.SQL_SettingManagedIdentityWithCredential, authenticationMode));
return ADP.InvalidOperation(System.StringsHelper.GetString(Strings.SQL_SettingNonInteractiveWithCredential, authenticationMode));
}
static internal Exception SettingCredentialWithIntegratedArgument()
{
Expand All @@ -315,9 +315,9 @@ static internal Exception SettingCredentialWithDeviceFlowArgument()
{
return ADP.Argument(System.StringsHelper.GetString(Strings.SQL_SettingCredentialWithDeviceFlow));
}
static internal Exception SettingCredentialWithManagedIdentityArgument(string authenticationMode)
static internal Exception SettingCredentialWithNonInteractiveArgument(string authenticationMode)
{
return ADP.Argument(System.StringsHelper.GetString(Strings.SQL_SettingCredentialWithManagedIdentity, authenticationMode));
return ADP.Argument(System.StringsHelper.GetString(Strings.SQL_SettingCredentialWithNonInteractive, authenticationMode));
}
static internal Exception SettingCredentialWithIntegratedInvalid()
{
Expand All @@ -331,9 +331,9 @@ static internal Exception SettingCredentialWithDeviceFlowInvalid()
{
return ADP.InvalidOperation(System.StringsHelper.GetString(Strings.SQL_SettingCredentialWithDeviceFlow));
}
static internal Exception SettingCredentialWithManagedIdentityInvalid(string authenticationMode)
static internal Exception SettingCredentialWithNonInteractiveInvalid(string authenticationMode)
{
return ADP.InvalidOperation(System.StringsHelper.GetString(Strings.SQL_SettingCredentialWithManagedIdentity, authenticationMode));
return ADP.InvalidOperation(System.StringsHelper.GetString(Strings.SQL_SettingCredentialWithNonInteractive, authenticationMode));
}
internal static Exception NullEmptyTransactionName()
{
Expand Down

0 comments on commit 6a390fe

Please sign in to comment.