Skip to content

Commit

Permalink
Fix get_ConnectionTimeout property API in SqlAuthenticationParameters (
Browse files Browse the repository at this point in the history
  • Loading branch information
cheenamalhotra authored Oct 15, 2021
1 parent 12fafc2 commit 47ff527
Show file tree
Hide file tree
Showing 5 changed files with 78 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ public enum SqlAuthenticationMethod
SqlPassword = 1
}
/// <include file='../../../../doc/snippets/Microsoft.Data.SqlClient/SqlAuthenticationParameters.xml' path='docs/members[@name="SqlAuthenticationParameters"]/SqlAuthenticationParameters/*'/>
public partial class SqlAuthenticationParameters
public class SqlAuthenticationParameters
{
/// <include file='../../../../doc/snippets/Microsoft.Data.SqlClient/SqlAuthenticationParameters.xml' path='docs/members[@name="SqlAuthenticationParameters"]/ctor/*'/>
protected SqlAuthenticationParameters(Microsoft.Data.SqlClient.SqlAuthenticationMethod authenticationMethod, string serverName, string databaseName, string resource, string authority, string userId, string password, System.Guid connectionId, int connectionTimeout) { }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ public enum SqlAuthenticationMethod
SqlPassword = 1
}
/// <include file='../../../../doc/snippets/Microsoft.Data.SqlClient/SqlAuthenticationParameters.xml' path='docs/members[@name="SqlAuthenticationParameters"]/SqlAuthenticationParameters/*'/>
public partial class SqlAuthenticationParameters
public class SqlAuthenticationParameters
{
/// <include file='../../../../doc/snippets/Microsoft.Data.SqlClient/SqlAuthenticationParameters.xml' path='docs/members[@name="SqlAuthenticationParameters"]/ctor/*'/>
protected SqlAuthenticationParameters(Microsoft.Data.SqlClient.SqlAuthenticationMethod authenticationMethod, string serverName, string databaseName, string resource, string authority, string userId, string password, System.Guid connectionId, int connectionTimeout) { }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ public class SqlAuthenticationParameters
public string DatabaseName { get; }

/// <include file='../../../../../../doc/snippets/Microsoft.Data.SqlClient/SqlAuthenticationParameters.xml' path='docs/members[@name="SqlAuthenticationParameters"]/ConnectionTimeout/*'/>
public int ConnectionTimeout = ADP.DefaultConnectionTimeout;
public int ConnectionTimeout { get; } = ADP.DefaultConnectionTimeout;

/// <include file='../../../../../../doc/snippets/Microsoft.Data.SqlClient/SqlAuthenticationParameters.xml' path='docs/members[@name="SqlAuthenticationParameters"]/ctor/*'/>
protected SqlAuthenticationParameters(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ public static class DataTestUtility
public static string AADAccessToken = null;
public static string AADSystemIdentityAccessToken = null;
public static string AADUserIdentityAccessToken = null;
public const string ApplicationClientId = "2fd908ad-0664-4344-b9be-cd3e8b574c38";
public const string UdtTestDbName = "UdtTestDb";
public const string AKVKeyName = "TestSqlClientAzureKeyVaultProvider";
public const string EventSourcePrefix = "Microsoft.Data.SqlClient";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,57 @@
using System;
using System.Diagnostics;
using System.Security;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Identity.Client;
using Xunit;

namespace Microsoft.Data.SqlClient.ManualTesting.Tests
{
public class AADConnectionsTest
{
class CustomSqlAuthenticationProvider : SqlAuthenticationProvider
{
string _appClientId;

internal CustomSqlAuthenticationProvider(string appClientId)
{
_appClientId = appClientId;
}

public override async Task<SqlAuthenticationToken> AcquireTokenAsync(SqlAuthenticationParameters parameters)
{
string s_defaultScopeSuffix = "/.default";
string scope = parameters.Resource.EndsWith(s_defaultScopeSuffix) ? parameters.Resource : parameters.Resource + s_defaultScopeSuffix;

_ = parameters.ServerName;
_ = parameters.DatabaseName;
_ = parameters.ConnectionId;

var cts = new CancellationTokenSource();
cts.CancelAfter(parameters.ConnectionTimeout * 1000);

string[] scopes = new string[] { scope };
SecureString password = new SecureString();
foreach (char c in parameters.Password)
password.AppendChar(c);
password.MakeReadOnly();

AuthenticationResult result = await PublicClientApplicationBuilder.Create(_appClientId)
.WithAuthority(parameters.Authority)
.Build().AcquireTokenByUsernamePassword(scopes, parameters.UserId, password)
.WithCorrelationId(parameters.ConnectionId)
.ExecuteAsync(cancellationToken: cts.Token);

return new SqlAuthenticationToken(result.AccessToken, result.ExpiresOn);
}

public override bool IsSupported(SqlAuthenticationMethod authenticationMethod)
{
return authenticationMethod.Equals(SqlAuthenticationMethod.ActiveDirectoryPassword);
}
}

private static void ConnectAndDisconnect(string connectionString, SqlCredential credential = null)
{
using (SqlConnection conn = new SqlConnection(connectionString))
Expand Down Expand Up @@ -167,7 +212,6 @@ public static void AADPasswordWithWrongPassword()
Assert.Contains(expectedMessage, e.Message);
}


[ConditionalFact(nameof(IsAADConnStringsSetup))]
public static void GetAccessTokenByPasswordTest()
{
Expand All @@ -181,7 +225,7 @@ public static void GetAccessTokenByPasswordTest()
}

[ConditionalFact(nameof(IsAADConnStringsSetup))]
public static void testADPasswordAuthentication()
public static void TestADPasswordAuthentication()
{
// Connect to Azure DB with password and retrieve user name.
using (SqlConnection conn = new SqlConnection(DataTestUtility.AADPasswordConnectionString))
Expand All @@ -201,6 +245,30 @@ public static void testADPasswordAuthentication()
}
}

[ConditionalFact(nameof(IsAADConnStringsSetup))]
public static void TestCustomProviderAuthentication()
{
SqlAuthenticationProvider.SetProvider(SqlAuthenticationMethod.ActiveDirectoryPassword, new CustomSqlAuthenticationProvider(DataTestUtility.ApplicationClientId));
// Connect to Azure DB with password and retrieve user name using custom authentication provider
using (SqlConnection conn = new SqlConnection(DataTestUtility.AADPasswordConnectionString))
{
conn.Open();
using (SqlCommand sqlCommand = new SqlCommand
(
cmdText: $"SELECT SUSER_SNAME();",
connection: conn,
transaction: null
))
{
string customerId = (string)sqlCommand.ExecuteScalar();
string expected = DataTestUtility.RetrieveValueFromConnStr(DataTestUtility.AADPasswordConnectionString, new string[] { "User ID", "UID" });
Assert.Equal(expected, customerId);
}
}
// Reset to driver internal provider.
SqlAuthenticationProvider.SetProvider(SqlAuthenticationMethod.ActiveDirectoryPassword, new ActiveDirectoryAuthenticationProvider(DataTestUtility.ApplicationClientId));
}

[ConditionalFact(nameof(IsAADConnStringsSetup))]
public static void ActiveDirectoryPasswordWithNoAuthType()
{
Expand Down Expand Up @@ -269,7 +337,7 @@ public static void EmptyCredInConnStrAADPasswordAnyUnix()
string[] removeKeys = { "User ID", "Password", "UID", "PWD" };
string connStr = DataTestUtility.RemoveKeysInConnStr(DataTestUtility.AADPasswordConnectionString, removeKeys) + "User ID=; Password=;";
SqlException e = Assert.Throws<SqlException>(() => ConnectAndDisconnect(connStr));

string expectedMessage = "MSAL cannot determine the username (UPN) of the currently logged in user.For Integrated Windows Authentication and Username/Password flows, please use .WithUsername() before calling ExecuteAsync().";
Assert.Contains(expectedMessage, e.Message);
}
Expand Down Expand Up @@ -504,13 +572,13 @@ public static void ADInteractiveUsingSSPI()
public static void ConnectionSpeed()
{
var connString = DataTestUtility.AADPasswordConnectionString;

//Ensure server endpoints are warm
using (var connectionDrill = new SqlConnection(connString))
{
connectionDrill.Open();
}

SqlConnection.ClearAllPools();
ActiveDirectoryAuthenticationProvider.ClearUserTokenCache();

Expand All @@ -529,7 +597,7 @@ public static void ConnectionSpeed()
secondConnectionTime.Stop();
}
}

// Subsequent AAD connections within a short timeframe should use an auth token cached from the connection pool
// Second connection speed in tests was typically 10-15% of the first connection time. Using 30% since speeds may vary.
Assert.True(((double)secondConnectionTime.ElapsedMilliseconds / firstConnectionTime.ElapsedMilliseconds) < 0.30, $"Second AAD connection too slow ({secondConnectionTime.ElapsedMilliseconds}ms)! (More than 30% of the first ({firstConnectionTime.ElapsedMilliseconds}ms).)");
Expand Down

0 comments on commit 47ff527

Please sign in to comment.