Skip to content

Commit d14c0b1

Browse files
Feature | Add support for user-defined ApplicationClientId (#740)
1 parent 81052d6 commit d14c0b1

File tree

11 files changed

+115
-24
lines changed

11 files changed

+115
-24
lines changed
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
//<Snippet1>
2+
using System;
3+
using Microsoft.Data.SqlClient;
4+
5+
namespace CustomAuthenticationProviderExamples
6+
{
7+
public class Program
8+
{
9+
public static void Main()
10+
{
11+
// Supported for all authentication modes supported by ActiveDirectoryAuthenticationProvider
12+
ActiveDirectoryAuthenticationProvider provider = new ActiveDirectoryAuthenticationProvider("<application_client_id>");
13+
if (provider.IsSupported(SqlAuthenticationMethod.ActiveDirectoryInteractive))
14+
{
15+
SqlAuthenticationProvider.SetProvider(SqlAuthenticationMethod.ActiveDirectoryInteractive, provider);
16+
}
17+
18+
using (SqlConnection sqlConnection = new SqlConnection("Server=<myserver>.database.windows.net;Authentication=Active Directory Interactive;Database=<db>;"))
19+
{
20+
sqlConnection.Open();
21+
Console.WriteLine("Connected successfully!");
22+
}
23+
}
24+
}
25+
}
26+
//</Snippet1>

doc/snippets/Microsoft.Data.SqlClient/ActiveDirectoryAuthenticationProvider.xml

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,19 +11,38 @@
1111
</summary>
1212
</ctor>
1313
<ctor2>
14-
<param name="deviceCodeFlowCallbackMethod">The callback method to be used when performing 'Active Directory Device Code Flow' authentication.</param>
14+
<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>
1515
<summary>
16-
Initializes the <see cref="T:Microsoft.Data.SqlClient.ActiveDirectoryAuthenticationProvider" /> class with the provided device code flow callback method.
16+
Initializes the <see cref="T:Microsoft.Data.SqlClient.ActiveDirectoryAuthenticationProvider" /> class with the provided application client id.
1717
</summary>
18+
<remarks>
19+
<format type="text/markdown">
20+
<![CDATA[
21+
22+
## Examples
23+
The following example demonstrates providing a user-defined application client id to SqlClient for the "Active Directory Interactive" authentication method:
24+
25+
[!code-csharp[ActiveDirectory_ApplicationClientId Example#1](~/../sqlclient/doc/samples/ApplicationClientIdAzureAuthenticationProvider.cs#1)]
26+
27+
]]>
28+
</format>
29+
</remarks>
1830
</ctor2>
31+
<ctor3>
32+
<param name="deviceCodeFlowCallbackMethod">The callback method to be used with 'Active Directory Device Code Flow' authentication.</param>
33+
<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>
34+
<summary>
35+
Initializes the <see cref="T:Microsoft.Data.SqlClient.ActiveDirectoryAuthenticationProvider" /> class with the provided device code flow callback method and application client id.
36+
</summary>
37+
</ctor3>
1938
<AcquireTokenAsync>
2039
<param name="parameters">The Active Directory authentication parameters passed to authentication providers.</param>
2140
<summary>Acquires a security token from the authority.</summary>
2241
<returns>Represents an asynchronous operation that returns the authentication token.</returns>
2342
</AcquireTokenAsync>
2443
<SetDeviceCodeFlowCallback>
25-
<param name="deviceCodeFlowCallbackMethod">The callback method to be used when performing 'Active Directory Device Code Flow' authentication.</param>
26-
<summary>Sets the callback method, overriding the default implementation that processes the result when performing 'Active Directory Device Code Flow' authentication.</summary>
44+
<param name="deviceCodeFlowCallbackMethod">The callback method to be used with 'Active Directory Device Code Flow' authentication.</param>
45+
<summary>Sets the callback method, overriding the default implementation that processes the result for 'Active Directory Device Code Flow' authentication.</summary>
2746
</SetDeviceCodeFlowCallback>
2847
<SetParentActivityOrWindowFunc>
2948
<param name="parentActivityOrWindowFunc">The parent as an object, in order to be used from shared .NET Standard assemblies.</param>

src/Microsoft.Data.SqlClient/netcore/ref/Microsoft.Data.SqlClient.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,9 @@ public sealed partial class ActiveDirectoryAuthenticationProvider : SqlAuthentic
3636
/// <include file='../../../../doc/snippets/Microsoft.Data.SqlClient/ActiveDirectoryAuthenticationProvider.xml' path='docs/members[@name="ActiveDirectoryAuthenticationProvider"]/ctor/*'/>
3737
public ActiveDirectoryAuthenticationProvider() { }
3838
/// <include file='../../../../doc/snippets/Microsoft.Data.SqlClient/ActiveDirectoryAuthenticationProvider.xml' path='docs/members[@name="ActiveDirectoryAuthenticationProvider"]/ctor2/*'/>
39-
public ActiveDirectoryAuthenticationProvider(System.Func<Microsoft.Identity.Client.DeviceCodeResult, System.Threading.Tasks.Task> deviceCodeFlowCallbackMethod) { }
39+
public ActiveDirectoryAuthenticationProvider(string applicationClientId) { }
40+
/// <include file='../../../../doc/snippets/Microsoft.Data.SqlClient/ActiveDirectoryAuthenticationProvider.xml' path='docs/members[@name="ActiveDirectoryAuthenticationProvider"]/ctor3/*'/>
41+
public ActiveDirectoryAuthenticationProvider(System.Func<Microsoft.Identity.Client.DeviceCodeResult, System.Threading.Tasks.Task> deviceCodeFlowCallbackMethod, string applicationClientId = null) { }
4042
/// <include file='../../../../doc/snippets/Microsoft.Data.SqlClient/ActiveDirectoryAuthenticationProvider.xml' path='docs/members[@name="ActiveDirectoryAuthenticationProvider"]/AcquireTokenAsync/*'/>
4143
public override System.Threading.Tasks.Task<SqlAuthenticationToken> AcquireTokenAsync(SqlAuthenticationParameters parameters) { throw null; }
4244
/// <include file='../../../../doc/snippets/Microsoft.Data.SqlClient/ActiveDirectoryAuthenticationProvider.xml' path='docs/members[@name="ActiveDirectoryAuthenticationProvider"]/SetDeviceCodeFlowCallback/*'/>

src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlAuthenticationProviderManager.NetCoreApp.cs

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ internal partial class SqlAuthenticationProviderManager
1515

1616
static SqlAuthenticationProviderManager()
1717
{
18-
var activeDirectoryAuthProvider = new ActiveDirectoryAuthenticationProvider();
1918
SqlAuthenticationProviderConfigurationSection configurationSection = null;
2019

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

3736
Instance = new SqlAuthenticationProviderManager(configurationSection);
37+
var activeDirectoryAuthProvider = new ActiveDirectoryAuthenticationProvider(Instance._applicationClientId);
3838
Instance.SetProvider(SqlAuthenticationMethod.ActiveDirectoryIntegrated, activeDirectoryAuthProvider);
3939
Instance.SetProvider(SqlAuthenticationMethod.ActiveDirectoryPassword, activeDirectoryAuthProvider);
4040
Instance.SetProvider(SqlAuthenticationMethod.ActiveDirectoryInteractive, activeDirectoryAuthProvider);
@@ -59,6 +59,16 @@ public SqlAuthenticationProviderManager(SqlAuthenticationProviderConfigurationSe
5959
return;
6060
}
6161

62+
if (!string.IsNullOrEmpty(configSection.ApplicationClientId))
63+
{
64+
_applicationClientId = configSection.ApplicationClientId;
65+
_sqlAuthLogger.LogInfo(_typeName, methodName, "Received user-defined Application Client Id");
66+
}
67+
else
68+
{
69+
_sqlAuthLogger.LogInfo(_typeName, methodName, "No user-defined Application Client Id found.");
70+
}
71+
6272
// Create user-defined auth initializer, if any.
6373
if (!string.IsNullOrEmpty(configSection.InitializerType))
6474
{
@@ -159,13 +169,19 @@ internal class SqlAuthenticationProviderConfigurationSection : ConfigurationSect
159169
/// User-defined auth providers.
160170
/// </summary>
161171
[ConfigurationProperty("providers")]
162-
public ProviderSettingsCollection Providers => (ProviderSettingsCollection)base["providers"];
172+
public ProviderSettingsCollection Providers => (ProviderSettingsCollection)this["providers"];
163173

164174
/// <summary>
165175
/// User-defined initializer.
166176
/// </summary>
167177
[ConfigurationProperty("initializerType")]
168-
public string InitializerType => base["initializerType"] as string;
178+
public string InitializerType => this["initializerType"] as string;
179+
180+
/// <summary>
181+
/// Application Client Id
182+
/// </summary>
183+
[ConfigurationProperty("applicationClientId", IsRequired = false)]
184+
public string ApplicationClientId => this["applicationClientId"] as string;
169185
}
170186

171187
/// <summary>

src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlAuthenticationProviderManager.NetStandard.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ internal partial class SqlAuthenticationProviderManager
88
{
99
static SqlAuthenticationProviderManager()
1010
{
11-
var activeDirectoryAuthProvider = new ActiveDirectoryAuthenticationProvider();
1211
Instance = new SqlAuthenticationProviderManager();
12+
var activeDirectoryAuthProvider = new ActiveDirectoryAuthenticationProvider(Instance._applicationClientId);
1313
Instance.SetProvider(SqlAuthenticationMethod.ActiveDirectoryPassword, activeDirectoryAuthProvider);
1414
Instance.SetProvider(SqlAuthenticationMethod.ActiveDirectoryIntegrated, activeDirectoryAuthProvider);
1515
Instance.SetProvider(SqlAuthenticationMethod.ActiveDirectoryInteractive, activeDirectoryAuthProvider);

src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlAuthenticationProviderManager.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ internal partial class SqlAuthenticationProviderManager
2424
private readonly IReadOnlyCollection<SqlAuthenticationMethod> _authenticationsWithAppSpecifiedProvider;
2525
private readonly ConcurrentDictionary<SqlAuthenticationMethod, SqlAuthenticationProvider> _providers;
2626
private readonly SqlClientLogger _sqlAuthLogger = new SqlClientLogger();
27+
private readonly string _applicationClientId = ActiveDirectoryAuthentication.AdoClientId;
2728

2829
public static readonly SqlAuthenticationProviderManager Instance;
2930

src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlUtil.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -903,11 +903,11 @@ internal static Exception BulkLoadUnspecifiedSortOrder()
903903
internal static Exception BulkLoadInvalidOrderHint()
904904
{
905905
return ADP.Argument(System.StringsHelper.GetString(Strings.SQL_BulkLoadInvalidOrderHint));
906-
}
906+
}
907907
internal static Exception BulkLoadOrderHintInvalidColumn(string columnName)
908908
{
909909
return ADP.InvalidOperation(string.Format(System.StringsHelper.GetString(Strings.SQL_BulkLoadOrderHintInvalidColumn), columnName));
910-
}
910+
}
911911
internal static Exception BulkLoadOrderHintDuplicateColumn(string columnName)
912912
{
913913
return ADP.InvalidOperation(string.Format(System.StringsHelper.GetString(Strings.SQL_BulkLoadOrderHintDuplicateColumn), columnName));

src/Microsoft.Data.SqlClient/netfx/ref/Microsoft.Data.SqlClient.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,9 @@ public sealed class ActiveDirectoryAuthenticationProvider : SqlAuthenticationPro
4141
/// <include file='../../../../doc/snippets/Microsoft.Data.SqlClient/ActiveDirectoryAuthenticationProvider.xml' path='docs/members[@name="ActiveDirectoryAuthenticationProvider"]/ctor/*'/>
4242
public ActiveDirectoryAuthenticationProvider() { }
4343
/// <include file='../../../../doc/snippets/Microsoft.Data.SqlClient/ActiveDirectoryAuthenticationProvider.xml' path='docs/members[@name="ActiveDirectoryAuthenticationProvider"]/ctor2/*'/>
44-
public ActiveDirectoryAuthenticationProvider(System.Func<Microsoft.Identity.Client.DeviceCodeResult, System.Threading.Tasks.Task> deviceCodeFlowCallbackMethod) { }
44+
public ActiveDirectoryAuthenticationProvider(string applicationClientId) { }
45+
/// <include file='../../../../doc/snippets/Microsoft.Data.SqlClient/ActiveDirectoryAuthenticationProvider.xml' path='docs/members[@name="ActiveDirectoryAuthenticationProvider"]/ctor3/*'/>
46+
public ActiveDirectoryAuthenticationProvider(System.Func<Microsoft.Identity.Client.DeviceCodeResult, System.Threading.Tasks.Task> deviceCodeFlowCallbackMethod, string applicationClientId = null) { }
4547
/// <include file='../../../../doc/snippets/Microsoft.Data.SqlClient/ActiveDirectoryAuthenticationProvider.xml' path='docs/members[@name="ActiveDirectoryAuthenticationProvider"]/AcquireTokenAsync/*'/>
4648
public override System.Threading.Tasks.Task<SqlAuthenticationToken> AcquireTokenAsync(SqlAuthenticationParameters parameters) { throw null; }
4749
/// <include file='../../../../doc/snippets/Microsoft.Data.SqlClient/ActiveDirectoryAuthenticationProvider.xml' path='docs/members[@name="ActiveDirectoryAuthenticationProvider"]/SetDeviceCodeFlowCallback/*'/>

src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlAuthenticationProviderManager.cs

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ internal class SqlAuthenticationProviderManager
2323

2424
static SqlAuthenticationProviderManager()
2525
{
26-
var activeDirectoryAuthProvider = new ActiveDirectoryAuthenticationProvider();
2726
SqlAuthenticationProviderConfigurationSection configurationSection = null;
2827
try
2928
{
@@ -38,9 +37,11 @@ static SqlAuthenticationProviderManager()
3837
catch (ConfigurationErrorsException e)
3938
{
4039
// Don't throw an error for invalid config files
41-
SqlClientEventSource.Log.TryTraceEvent("Unable to load custom SqlAuthenticationProviders or SqlClientAuthenticationProviders. ConfigurationManager failed to load due to configuration errors: {0}", e);
40+
SqlClientEventSource.Log.TryTraceEvent("static SqlAuthenticationProviderManager: Unable to load custom SqlAuthenticationProviders or SqlClientAuthenticationProviders. ConfigurationManager failed to load due to configuration errors: {0}", e);
4241
}
4342
Instance = new SqlAuthenticationProviderManager(configurationSection);
43+
44+
var activeDirectoryAuthProvider = new ActiveDirectoryAuthenticationProvider(Instance._applicationClientId);
4445
Instance.SetProvider(SqlAuthenticationMethod.ActiveDirectoryIntegrated, activeDirectoryAuthProvider);
4546
Instance.SetProvider(SqlAuthenticationMethod.ActiveDirectoryPassword, activeDirectoryAuthProvider);
4647
Instance.SetProvider(SqlAuthenticationMethod.ActiveDirectoryInteractive, activeDirectoryAuthProvider);
@@ -54,6 +55,7 @@ static SqlAuthenticationProviderManager()
5455
private readonly IReadOnlyCollection<SqlAuthenticationMethod> _authenticationsWithAppSpecifiedProvider;
5556
private readonly ConcurrentDictionary<SqlAuthenticationMethod, SqlAuthenticationProvider> _providers;
5657
private readonly SqlClientLogger _sqlAuthLogger = new SqlClientLogger();
58+
private readonly string _applicationClientId = ActiveDirectoryAuthentication.AdoClientId;
5759

5860
/// <summary>
5961
/// Constructor.
@@ -72,8 +74,17 @@ public SqlAuthenticationProviderManager(SqlAuthenticationProviderConfigurationSe
7274
return;
7375
}
7476

77+
if (!string.IsNullOrEmpty(configSection.ApplicationClientId))
78+
{
79+
_applicationClientId = configSection.ApplicationClientId;
80+
_sqlAuthLogger.LogInfo(_typeName, methodName, "Received user-defined Application Client Id");
81+
}
82+
else
83+
{
84+
_sqlAuthLogger.LogInfo(_typeName, methodName, "No user-defined Application Client Id found.");
85+
}
86+
7587
// Create user-defined auth initializer, if any.
76-
//
7788
if (!string.IsNullOrEmpty(configSection.InitializerType))
7889
{
7990
try
@@ -226,13 +237,19 @@ internal class SqlAuthenticationProviderConfigurationSection : ConfigurationSect
226237
/// User-defined auth providers.
227238
/// </summary>
228239
[ConfigurationProperty("providers")]
229-
public ProviderSettingsCollection Providers => (ProviderSettingsCollection)base["providers"];
240+
public ProviderSettingsCollection Providers => (ProviderSettingsCollection)this["providers"];
230241

231242
/// <summary>
232243
/// User-defined initializer.
233244
/// </summary>
234245
[ConfigurationProperty("initializerType")]
235-
public string InitializerType => base["initializerType"] as string;
246+
public string InitializerType => this["initializerType"] as string;
247+
248+
/// <summary>
249+
/// Application Client Id
250+
/// </summary>
251+
[ConfigurationProperty("applicationClientId", IsRequired = false)]
252+
public string ApplicationClientId => this["applicationClientId"] as string;
236253
}
237254

238255
/// <summary>

src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlUtil.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -772,7 +772,7 @@ static internal Exception UDTUnexpectedResult(string exceptionText)
772772
static internal Exception CannotCompleteDelegatedTransactionWithOpenResults(SqlInternalConnectionTds internalConnection, bool marsOn)
773773
{
774774
SqlErrorCollection errors = new SqlErrorCollection();
775-
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));
775+
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));
776776
return SqlException.CreateException(errors, null, internalConnection);
777777
}
778778
static internal SysTx.TransactionPromotionException PromotionFailed(Exception inner)
@@ -858,7 +858,7 @@ static internal Exception UDTInvalidSqlType(string typeName)
858858
{
859859
return ADP.Argument(StringsHelper.GetString(Strings.SQLUDT_InvalidSqlType, typeName));
860860
}
861-
861+
862862
static internal Exception UDTInvalidSize(int maxSize, int maxSupportedSize)
863863
{
864864
throw ADP.ArgumentOutOfRange(StringsHelper.GetString(Strings.SQLUDT_InvalidSize, maxSize, maxSupportedSize));

0 commit comments

Comments
 (0)