Skip to content

Commit

Permalink
Feature | Add support for user-defined ApplicationClientId (#740)
Browse files Browse the repository at this point in the history
  • Loading branch information
cheenamalhotra authored Sep 28, 2020
1 parent 81052d6 commit d14c0b1
Show file tree
Hide file tree
Showing 11 changed files with 115 additions and 24 deletions.
26 changes: 26 additions & 0 deletions doc/samples/ApplicationClientIdAzureAuthenticationProvider.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
//<Snippet1>
using System;
using Microsoft.Data.SqlClient;

namespace CustomAuthenticationProviderExamples
{
public class Program
{
public static void Main()
{
// Supported for all authentication modes supported by ActiveDirectoryAuthenticationProvider
ActiveDirectoryAuthenticationProvider provider = new ActiveDirectoryAuthenticationProvider("<application_client_id>");
if (provider.IsSupported(SqlAuthenticationMethod.ActiveDirectoryInteractive))
{
SqlAuthenticationProvider.SetProvider(SqlAuthenticationMethod.ActiveDirectoryInteractive, provider);
}

using (SqlConnection sqlConnection = new SqlConnection("Server=<myserver>.database.windows.net;Authentication=Active Directory Interactive;Database=<db>;"))
{
sqlConnection.Open();
Console.WriteLine("Connected successfully!");
}
}
}
}
//</Snippet1>
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,38 @@
</summary>
</ctor>
<ctor2>
<param name="deviceCodeFlowCallbackMethod">The callback method to be used when performing 'Active Directory Device Code Flow' authentication.</param>
<param name="applicationClientId">Client Application Id to be used for acquiring an access token for federated authentication. The driver uses its own application client id by default.</param>
<summary>
Initializes the <see cref="T:Microsoft.Data.SqlClient.ActiveDirectoryAuthenticationProvider" /> class with the provided device code flow callback method.
Initializes the <see cref="T:Microsoft.Data.SqlClient.ActiveDirectoryAuthenticationProvider" /> class with the provided application client id.
</summary>
<remarks>
<format type="text/markdown">
<![CDATA[
## Examples
The following example demonstrates providing a user-defined application client id to SqlClient for the "Active Directory Interactive" authentication method:
[!code-csharp[ActiveDirectory_ApplicationClientId Example#1](~/../sqlclient/doc/samples/ApplicationClientIdAzureAuthenticationProvider.cs#1)]
]]>
</format>
</remarks>
</ctor2>
<ctor3>
<param name="deviceCodeFlowCallbackMethod">The callback method to be used with 'Active Directory Device Code Flow' authentication.</param>
<param name="applicationClientId">(Optional) Client Application Id to be used for acquiring an access token for federated authentication. The driver uses its own application client id by default.</param>
<summary>
Initializes the <see cref="T:Microsoft.Data.SqlClient.ActiveDirectoryAuthenticationProvider" /> class with the provided device code flow callback method and application client id.
</summary>
</ctor3>
<AcquireTokenAsync>
<param name="parameters">The Active Directory authentication parameters passed to authentication providers.</param>
<summary>Acquires a security token from the authority.</summary>
<returns>Represents an asynchronous operation that returns the authentication token.</returns>
</AcquireTokenAsync>
<SetDeviceCodeFlowCallback>
<param name="deviceCodeFlowCallbackMethod">The callback method to be used when performing 'Active Directory Device Code Flow' authentication.</param>
<summary>Sets the callback method, overriding the default implementation that processes the result when performing 'Active Directory Device Code Flow' authentication.</summary>
<param name="deviceCodeFlowCallbackMethod">The callback method to be used with 'Active Directory Device Code Flow' authentication.</param>
<summary>Sets the callback method, overriding the default implementation that processes the result for 'Active Directory Device Code Flow' authentication.</summary>
</SetDeviceCodeFlowCallback>
<SetParentActivityOrWindowFunc>
<param name="parentActivityOrWindowFunc">The parent as an object, in order to be used from shared .NET Standard assemblies.</param>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,9 @@ public sealed partial class ActiveDirectoryAuthenticationProvider : SqlAuthentic
/// <include file='../../../../doc/snippets/Microsoft.Data.SqlClient/ActiveDirectoryAuthenticationProvider.xml' path='docs/members[@name="ActiveDirectoryAuthenticationProvider"]/ctor/*'/>
public ActiveDirectoryAuthenticationProvider() { }
/// <include file='../../../../doc/snippets/Microsoft.Data.SqlClient/ActiveDirectoryAuthenticationProvider.xml' path='docs/members[@name="ActiveDirectoryAuthenticationProvider"]/ctor2/*'/>
public ActiveDirectoryAuthenticationProvider(System.Func<Microsoft.Identity.Client.DeviceCodeResult, System.Threading.Tasks.Task> deviceCodeFlowCallbackMethod) { }
public ActiveDirectoryAuthenticationProvider(string applicationClientId) { }
/// <include file='../../../../doc/snippets/Microsoft.Data.SqlClient/ActiveDirectoryAuthenticationProvider.xml' path='docs/members[@name="ActiveDirectoryAuthenticationProvider"]/ctor3/*'/>
public ActiveDirectoryAuthenticationProvider(System.Func<Microsoft.Identity.Client.DeviceCodeResult, System.Threading.Tasks.Task> deviceCodeFlowCallbackMethod, string applicationClientId = null) { }
/// <include file='../../../../doc/snippets/Microsoft.Data.SqlClient/ActiveDirectoryAuthenticationProvider.xml' path='docs/members[@name="ActiveDirectoryAuthenticationProvider"]/AcquireTokenAsync/*'/>
public override System.Threading.Tasks.Task<SqlAuthenticationToken> AcquireTokenAsync(SqlAuthenticationParameters parameters) { throw null; }
/// <include file='../../../../doc/snippets/Microsoft.Data.SqlClient/ActiveDirectoryAuthenticationProvider.xml' path='docs/members[@name="ActiveDirectoryAuthenticationProvider"]/SetDeviceCodeFlowCallback/*'/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ internal partial class SqlAuthenticationProviderManager

static SqlAuthenticationProviderManager()
{
var activeDirectoryAuthProvider = new ActiveDirectoryAuthenticationProvider();
SqlAuthenticationProviderConfigurationSection configurationSection = null;

try
Expand All @@ -31,10 +30,11 @@ static SqlAuthenticationProviderManager()
catch (ConfigurationErrorsException e)
{
// Don't throw an error for invalid config files
SqlClientEventSource.Log.TryTraceEvent("Unable to load custom SqlAuthenticationProviders or SqlClientAuthenticationProviders. ConfigurationManager failed to load due to configuration errors: {0}", e);
SqlClientEventSource.Log.TryTraceEvent("static SqlAuthenticationProviderManager: Unable to load custom SqlAuthenticationProviders or SqlClientAuthenticationProviders. ConfigurationManager failed to load due to configuration errors: {0}", e);
}

Instance = new SqlAuthenticationProviderManager(configurationSection);
var activeDirectoryAuthProvider = new ActiveDirectoryAuthenticationProvider(Instance._applicationClientId);
Instance.SetProvider(SqlAuthenticationMethod.ActiveDirectoryIntegrated, activeDirectoryAuthProvider);
Instance.SetProvider(SqlAuthenticationMethod.ActiveDirectoryPassword, activeDirectoryAuthProvider);
Instance.SetProvider(SqlAuthenticationMethod.ActiveDirectoryInteractive, activeDirectoryAuthProvider);
Expand All @@ -59,6 +59,16 @@ public SqlAuthenticationProviderManager(SqlAuthenticationProviderConfigurationSe
return;
}

if (!string.IsNullOrEmpty(configSection.ApplicationClientId))
{
_applicationClientId = configSection.ApplicationClientId;
_sqlAuthLogger.LogInfo(_typeName, methodName, "Received user-defined Application Client Id");
}
else
{
_sqlAuthLogger.LogInfo(_typeName, methodName, "No user-defined Application Client Id found.");
}

// Create user-defined auth initializer, if any.
if (!string.IsNullOrEmpty(configSection.InitializerType))
{
Expand Down Expand Up @@ -159,13 +169,19 @@ internal class SqlAuthenticationProviderConfigurationSection : ConfigurationSect
/// User-defined auth providers.
/// </summary>
[ConfigurationProperty("providers")]
public ProviderSettingsCollection Providers => (ProviderSettingsCollection)base["providers"];
public ProviderSettingsCollection Providers => (ProviderSettingsCollection)this["providers"];

/// <summary>
/// User-defined initializer.
/// </summary>
[ConfigurationProperty("initializerType")]
public string InitializerType => base["initializerType"] as string;
public string InitializerType => this["initializerType"] as string;

/// <summary>
/// Application Client Id
/// </summary>
[ConfigurationProperty("applicationClientId", IsRequired = false)]
public string ApplicationClientId => this["applicationClientId"] as string;
}

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ internal partial class SqlAuthenticationProviderManager
{
static SqlAuthenticationProviderManager()
{
var activeDirectoryAuthProvider = new ActiveDirectoryAuthenticationProvider();
Instance = new SqlAuthenticationProviderManager();
var activeDirectoryAuthProvider = new ActiveDirectoryAuthenticationProvider(Instance._applicationClientId);
Instance.SetProvider(SqlAuthenticationMethod.ActiveDirectoryPassword, activeDirectoryAuthProvider);
Instance.SetProvider(SqlAuthenticationMethod.ActiveDirectoryIntegrated, activeDirectoryAuthProvider);
Instance.SetProvider(SqlAuthenticationMethod.ActiveDirectoryInteractive, activeDirectoryAuthProvider);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ internal partial class SqlAuthenticationProviderManager
private readonly IReadOnlyCollection<SqlAuthenticationMethod> _authenticationsWithAppSpecifiedProvider;
private readonly ConcurrentDictionary<SqlAuthenticationMethod, SqlAuthenticationProvider> _providers;
private readonly SqlClientLogger _sqlAuthLogger = new SqlClientLogger();
private readonly string _applicationClientId = ActiveDirectoryAuthentication.AdoClientId;

public static readonly SqlAuthenticationProviderManager Instance;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -903,11 +903,11 @@ internal static Exception BulkLoadUnspecifiedSortOrder()
internal static Exception BulkLoadInvalidOrderHint()
{
return ADP.Argument(System.StringsHelper.GetString(Strings.SQL_BulkLoadInvalidOrderHint));
}
}
internal static Exception BulkLoadOrderHintInvalidColumn(string columnName)
{
return ADP.InvalidOperation(string.Format(System.StringsHelper.GetString(Strings.SQL_BulkLoadOrderHintInvalidColumn), columnName));
}
}
internal static Exception BulkLoadOrderHintDuplicateColumn(string columnName)
{
return ADP.InvalidOperation(string.Format(System.StringsHelper.GetString(Strings.SQL_BulkLoadOrderHintDuplicateColumn), columnName));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,9 @@ public sealed class ActiveDirectoryAuthenticationProvider : SqlAuthenticationPro
/// <include file='../../../../doc/snippets/Microsoft.Data.SqlClient/ActiveDirectoryAuthenticationProvider.xml' path='docs/members[@name="ActiveDirectoryAuthenticationProvider"]/ctor/*'/>
public ActiveDirectoryAuthenticationProvider() { }
/// <include file='../../../../doc/snippets/Microsoft.Data.SqlClient/ActiveDirectoryAuthenticationProvider.xml' path='docs/members[@name="ActiveDirectoryAuthenticationProvider"]/ctor2/*'/>
public ActiveDirectoryAuthenticationProvider(System.Func<Microsoft.Identity.Client.DeviceCodeResult, System.Threading.Tasks.Task> deviceCodeFlowCallbackMethod) { }
public ActiveDirectoryAuthenticationProvider(string applicationClientId) { }
/// <include file='../../../../doc/snippets/Microsoft.Data.SqlClient/ActiveDirectoryAuthenticationProvider.xml' path='docs/members[@name="ActiveDirectoryAuthenticationProvider"]/ctor3/*'/>
public ActiveDirectoryAuthenticationProvider(System.Func<Microsoft.Identity.Client.DeviceCodeResult, System.Threading.Tasks.Task> deviceCodeFlowCallbackMethod, string applicationClientId = null) { }
/// <include file='../../../../doc/snippets/Microsoft.Data.SqlClient/ActiveDirectoryAuthenticationProvider.xml' path='docs/members[@name="ActiveDirectoryAuthenticationProvider"]/AcquireTokenAsync/*'/>
public override System.Threading.Tasks.Task<SqlAuthenticationToken> AcquireTokenAsync(SqlAuthenticationParameters parameters) { throw null; }
/// <include file='../../../../doc/snippets/Microsoft.Data.SqlClient/ActiveDirectoryAuthenticationProvider.xml' path='docs/members[@name="ActiveDirectoryAuthenticationProvider"]/SetDeviceCodeFlowCallback/*'/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ internal class SqlAuthenticationProviderManager

static SqlAuthenticationProviderManager()
{
var activeDirectoryAuthProvider = new ActiveDirectoryAuthenticationProvider();
SqlAuthenticationProviderConfigurationSection configurationSection = null;
try
{
Expand All @@ -38,9 +37,11 @@ static SqlAuthenticationProviderManager()
catch (ConfigurationErrorsException e)
{
// Don't throw an error for invalid config files
SqlClientEventSource.Log.TryTraceEvent("Unable to load custom SqlAuthenticationProviders or SqlClientAuthenticationProviders. ConfigurationManager failed to load due to configuration errors: {0}", e);
SqlClientEventSource.Log.TryTraceEvent("static SqlAuthenticationProviderManager: Unable to load custom SqlAuthenticationProviders or SqlClientAuthenticationProviders. ConfigurationManager failed to load due to configuration errors: {0}", e);
}
Instance = new SqlAuthenticationProviderManager(configurationSection);

var activeDirectoryAuthProvider = new ActiveDirectoryAuthenticationProvider(Instance._applicationClientId);
Instance.SetProvider(SqlAuthenticationMethod.ActiveDirectoryIntegrated, activeDirectoryAuthProvider);
Instance.SetProvider(SqlAuthenticationMethod.ActiveDirectoryPassword, activeDirectoryAuthProvider);
Instance.SetProvider(SqlAuthenticationMethod.ActiveDirectoryInteractive, activeDirectoryAuthProvider);
Expand All @@ -54,6 +55,7 @@ static SqlAuthenticationProviderManager()
private readonly IReadOnlyCollection<SqlAuthenticationMethod> _authenticationsWithAppSpecifiedProvider;
private readonly ConcurrentDictionary<SqlAuthenticationMethod, SqlAuthenticationProvider> _providers;
private readonly SqlClientLogger _sqlAuthLogger = new SqlClientLogger();
private readonly string _applicationClientId = ActiveDirectoryAuthentication.AdoClientId;

/// <summary>
/// Constructor.
Expand All @@ -72,8 +74,17 @@ public SqlAuthenticationProviderManager(SqlAuthenticationProviderConfigurationSe
return;
}

if (!string.IsNullOrEmpty(configSection.ApplicationClientId))
{
_applicationClientId = configSection.ApplicationClientId;
_sqlAuthLogger.LogInfo(_typeName, methodName, "Received user-defined Application Client Id");
}
else
{
_sqlAuthLogger.LogInfo(_typeName, methodName, "No user-defined Application Client Id found.");
}

// Create user-defined auth initializer, if any.
//
if (!string.IsNullOrEmpty(configSection.InitializerType))
{
try
Expand Down Expand Up @@ -226,13 +237,19 @@ internal class SqlAuthenticationProviderConfigurationSection : ConfigurationSect
/// User-defined auth providers.
/// </summary>
[ConfigurationProperty("providers")]
public ProviderSettingsCollection Providers => (ProviderSettingsCollection)base["providers"];
public ProviderSettingsCollection Providers => (ProviderSettingsCollection)this["providers"];

/// <summary>
/// User-defined initializer.
/// </summary>
[ConfigurationProperty("initializerType")]
public string InitializerType => base["initializerType"] as string;
public string InitializerType => this["initializerType"] as string;

/// <summary>
/// Application Client Id
/// </summary>
[ConfigurationProperty("applicationClientId", IsRequired = false)]
public string ApplicationClientId => this["applicationClientId"] as string;
}

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -772,7 +772,7 @@ static internal Exception UDTUnexpectedResult(string exceptionText)
static internal Exception CannotCompleteDelegatedTransactionWithOpenResults(SqlInternalConnectionTds internalConnection, bool marsOn)
{
SqlErrorCollection errors = new SqlErrorCollection();
errors.Add(new SqlError(TdsEnums.TIMEOUT_EXPIRED, (byte)0x00, TdsEnums.MIN_ERROR_CLASS, null, (StringsHelper.GetString(Strings.ADP_OpenReaderExists, marsOn? ADP.Command : ADP.Connection)), "", 0, TdsEnums.SNI_WAIT_TIMEOUT));
errors.Add(new SqlError(TdsEnums.TIMEOUT_EXPIRED, (byte)0x00, TdsEnums.MIN_ERROR_CLASS, null, (StringsHelper.GetString(Strings.ADP_OpenReaderExists, marsOn ? ADP.Command : ADP.Connection)), "", 0, TdsEnums.SNI_WAIT_TIMEOUT));
return SqlException.CreateException(errors, null, internalConnection);
}
static internal SysTx.TransactionPromotionException PromotionFailed(Exception inner)
Expand Down Expand Up @@ -858,7 +858,7 @@ static internal Exception UDTInvalidSqlType(string typeName)
{
return ADP.Argument(StringsHelper.GetString(Strings.SQLUDT_InvalidSqlType, typeName));
}

static internal Exception UDTInvalidSize(int maxSize, int maxSupportedSize)
{
throw ADP.ArgumentOutOfRange(StringsHelper.GetString(Strings.SQLUDT_InvalidSize, maxSize, maxSupportedSize));
Expand Down
Loading

0 comments on commit d14c0b1

Please sign in to comment.