diff --git a/doc/snippets/Microsoft.Data.SqlClient/ActiveDirectoryAuthenticationProvider.xml b/doc/snippets/Microsoft.Data.SqlClient/ActiveDirectoryAuthenticationProvider.xml index 990c162acb..d3d6322a1b 100644 --- a/doc/snippets/Microsoft.Data.SqlClient/ActiveDirectoryAuthenticationProvider.xml +++ b/doc/snippets/Microsoft.Data.SqlClient/ActiveDirectoryAuthenticationProvider.xml @@ -40,6 +40,10 @@ Acquires a security token from the authority. Represents an asynchronous operation that returns the authentication token. + + Clears cached user tokens from the token provider. + This will cause interactive authentication prompts to appear again if tokens were previously being obtained from the cache. + The callback method to be used with 'Active Directory Device Code Flow' authentication. Sets the callback method, overriding the default implementation that processes the result for 'Active Directory Device Code Flow' authentication. 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 c528e8b800..3cf24e9810 100644 --- a/src/Microsoft.Data.SqlClient/netcore/ref/Microsoft.Data.SqlClient.cs +++ b/src/Microsoft.Data.SqlClient/netcore/ref/Microsoft.Data.SqlClient.cs @@ -37,6 +37,8 @@ public sealed partial class ActiveDirectoryAuthenticationProvider : SqlAuthentic public ActiveDirectoryAuthenticationProvider() { } /// public ActiveDirectoryAuthenticationProvider(string applicationClientId) { } + /// + public static void ClearUserTokenCache() { } /// public ActiveDirectoryAuthenticationProvider(System.Func deviceCodeFlowCallbackMethod, string applicationClientId = null) { } /// diff --git a/src/Microsoft.Data.SqlClient/netfx/ref/Microsoft.Data.SqlClient.cs b/src/Microsoft.Data.SqlClient/netfx/ref/Microsoft.Data.SqlClient.cs index 664215e020..9192733060 100644 --- a/src/Microsoft.Data.SqlClient/netfx/ref/Microsoft.Data.SqlClient.cs +++ b/src/Microsoft.Data.SqlClient/netfx/ref/Microsoft.Data.SqlClient.cs @@ -42,6 +42,8 @@ public sealed class ActiveDirectoryAuthenticationProvider : SqlAuthenticationPro public ActiveDirectoryAuthenticationProvider() { } /// public ActiveDirectoryAuthenticationProvider(string applicationClientId) { } + /// + public static void ClearUserTokenCache() { } /// public ActiveDirectoryAuthenticationProvider(System.Func deviceCodeFlowCallbackMethod, string applicationClientId = null) { } /// 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 2421511e62..29500ef5b4 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/ActiveDirectoryAuthenticationProvider.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/ActiveDirectoryAuthenticationProvider.cs @@ -47,6 +47,15 @@ public ActiveDirectoryAuthenticationProvider(Func device SetDeviceCodeFlowCallback(deviceCodeFlowCallbackMethod); } + /// + public static void ClearUserTokenCache() + { + if (!s_pcaMap.IsEmpty) + { + s_pcaMap.Clear(); + } + } + /// public void SetDeviceCodeFlowCallback(Func deviceCodeFlowCallbackMethod) => _deviceCodeFlowCallback = deviceCodeFlowCallbackMethod; @@ -190,8 +199,8 @@ public override Task AcquireTokenAsync(SqlAuthentication } catch (MsalUiRequiredException) { - // An 'MsalUiRequiredException' is thrown in the case where an interaction is required with the end user of the application, - // for instance, if no refresh token was in the cache, or the user needs to consent, or re-sign-in (for instance if the password expired), + // An 'MsalUiRequiredException' is thrown in the case where an interaction is required with the end user of the application, + // for instance, if no refresh token was in the cache, or the user needs to consent, or re-sign-in (for instance if the password expired), // or the user needs to perform two factor authentication. result = await AcquireTokenInteractiveDeviceFlowAsync(app, scopes, parameters.ConnectionId, parameters.UserId, parameters.AuthenticationMethod); SqlClientEventSource.Log.TryTraceEvent("AcquireTokenAsync | Acquired access token (interactive) for {0} auth mode. Expiry Time: {1}", parameters.AuthenticationMethod, result.ExpiresOn); 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 e8396b0b4c..d823c05b87 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectivityTests/AADConnectionTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectivityTests/AADConnectionTest.cs @@ -171,9 +171,12 @@ public static void AADPasswordWithWrongPassword() [ConditionalFact(nameof(IsAADConnStringsSetup))] public static void GetAccessTokenByPasswordTest() { + // Clear token cache for code coverage. + ActiveDirectoryAuthenticationProvider.ClearUserTokenCache(); using (SqlConnection connection = new SqlConnection(DataTestUtility.AADPasswordConnectionString)) { connection.Open(); + Assert.True(connection.State == System.Data.ConnectionState.Open); } }