Skip to content

Commit

Permalink
Introduce new API to clear global Public Client Application instances…
Browse files Browse the repository at this point in the history
… holding User Token Cache (#800)

* Introduce new API to clear Public Client Application instances holding User Token Cache

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

Co-authored-by: David Engel <dengel@magnitude.com>

Co-authored-by: David Engel <dengel@magnitude.com>
  • Loading branch information
cheenamalhotra and David-Engel committed Nov 18, 2020
1 parent 5ebb548 commit f19cc8f
Show file tree
Hide file tree
Showing 5 changed files with 22 additions and 2 deletions.
Expand Up @@ -40,6 +40,10 @@
<summary>Acquires a security token from the authority.</summary>
<returns>Represents an asynchronous operation that returns the authentication token.</returns>
</AcquireTokenAsync>
<ClearUserTokenCache>
<summary>Clears cached user tokens from the token provider.</summary>
<remarks>This will cause interactive authentication prompts to appear again if tokens were previously being obtained from the cache.</remarks>
</ClearUserTokenCache>
<SetDeviceCodeFlowCallback>
<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>
Expand Down
Expand Up @@ -37,6 +37,8 @@ public sealed partial class ActiveDirectoryAuthenticationProvider : SqlAuthentic
public ActiveDirectoryAuthenticationProvider() { }
/// <include file='../../../../doc/snippets/Microsoft.Data.SqlClient/ActiveDirectoryAuthenticationProvider.xml' path='docs/members[@name="ActiveDirectoryAuthenticationProvider"]/ctor2/*'/>
public ActiveDirectoryAuthenticationProvider(string applicationClientId) { }
/// <include file='../../../../doc/snippets/Microsoft.Data.SqlClient/ActiveDirectoryAuthenticationProvider.xml' path='docs/members[@name="ActiveDirectoryAuthenticationProvider"]/ClearUserTokenCache/*'/>
public static void ClearUserTokenCache() { }
/// <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/*'/>
Expand Down
Expand Up @@ -42,6 +42,8 @@ public sealed class ActiveDirectoryAuthenticationProvider : SqlAuthenticationPro
public ActiveDirectoryAuthenticationProvider() { }
/// <include file='../../../../doc/snippets/Microsoft.Data.SqlClient/ActiveDirectoryAuthenticationProvider.xml' path='docs/members[@name="ActiveDirectoryAuthenticationProvider"]/ctor2/*'/>
public ActiveDirectoryAuthenticationProvider(string applicationClientId) { }
/// <include file='../../../../doc/snippets/Microsoft.Data.SqlClient/ActiveDirectoryAuthenticationProvider.xml' path='docs/members[@name="ActiveDirectoryAuthenticationProvider"]/ClearUserTokenCache/*'/>
public static void ClearUserTokenCache() { }
/// <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/*'/>
Expand Down
Expand Up @@ -47,6 +47,15 @@ public ActiveDirectoryAuthenticationProvider(Func<DeviceCodeResult, Task> device
SetDeviceCodeFlowCallback(deviceCodeFlowCallbackMethod);
}

/// <include file='../../../../../../doc/snippets/Microsoft.Data.SqlClient/ActiveDirectoryAuthenticationProvider.xml' path='docs/members[@name="ActiveDirectoryAuthenticationProvider"]/ClearUserTokenCache/*'/>
public static void ClearUserTokenCache()
{
if (!s_pcaMap.IsEmpty)
{
s_pcaMap.Clear();
}
}

/// <include file='../../../../../../doc/snippets/Microsoft.Data.SqlClient/ActiveDirectoryAuthenticationProvider.xml' path='docs/members[@name="ActiveDirectoryAuthenticationProvider"]/SetDeviceCodeFlowCallback/*'/>
public void SetDeviceCodeFlowCallback(Func<DeviceCodeResult, Task> deviceCodeFlowCallbackMethod) => _deviceCodeFlowCallback = deviceCodeFlowCallbackMethod;

Expand Down Expand Up @@ -190,8 +199,8 @@ public override void BeforeUnload(SqlAuthenticationMethod authentication)
}
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);
Expand Down
Expand Up @@ -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);
}
}

Expand Down

0 comments on commit f19cc8f

Please sign in to comment.