From ee39e1615f3332fb7e07cf5641fc25a44fe4760a Mon Sep 17 00:00:00 2001 From: Jenny Ferries Date: Fri, 26 Jun 2020 14:15:22 -0700 Subject: [PATCH 1/7] use MSAL token cache args cache key --- .../Microsoft.Identity.Web.csproj | 2 +- .../TokenAcquisition.cs | 4 +- .../IMsalTokenCacheProvider.cs | 3 +- .../MsalAbstractTokenCacheProvider.cs | 41 +++---------------- 4 files changed, 11 insertions(+), 39 deletions(-) diff --git a/src/Microsoft.Identity.Web/Microsoft.Identity.Web.csproj b/src/Microsoft.Identity.Web/Microsoft.Identity.Web.csproj index 86c53c856..8f6d8c376 100644 --- a/src/Microsoft.Identity.Web/Microsoft.Identity.Web.csproj +++ b/src/Microsoft.Identity.Web/Microsoft.Identity.Web.csproj @@ -83,7 +83,7 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/src/Microsoft.Identity.Web/TokenAcquisition.cs b/src/Microsoft.Identity.Web/TokenAcquisition.cs index af05852a0..3d60744c5 100644 --- a/src/Microsoft.Identity.Web/TokenAcquisition.cs +++ b/src/Microsoft.Identity.Web/TokenAcquisition.cs @@ -302,7 +302,7 @@ public async Task RemoveAccountAsync(RedirectContext context) await app.RemoveAsync(b2cAccount).ConfigureAwait(false); } - _tokenCacheProvider?.ClearAsync().ConfigureAwait(false); + _tokenCacheProvider?.ClearAsync(user.GetMsalAccountId()).ConfigureAwait(false); } else { @@ -312,7 +312,7 @@ public async Task RemoveAccountAsync(RedirectContext context) if (account != null) { await app.RemoveAsync(account).ConfigureAwait(false); - _tokenCacheProvider?.ClearAsync().ConfigureAwait(false); + _tokenCacheProvider?.ClearAsync(user.GetMsalAccountId()).ConfigureAwait(false); } } } diff --git a/src/Microsoft.Identity.Web/TokenCacheProviders/IMsalTokenCacheProvider.cs b/src/Microsoft.Identity.Web/TokenCacheProviders/IMsalTokenCacheProvider.cs index 4d773dd8e..a263dd6f1 100644 --- a/src/Microsoft.Identity.Web/TokenCacheProviders/IMsalTokenCacheProvider.cs +++ b/src/Microsoft.Identity.Web/TokenCacheProviders/IMsalTokenCacheProvider.cs @@ -21,7 +21,8 @@ public interface IMsalTokenCacheProvider /// /// Clear the cache. /// + /// HomeAccountId for a user account in the cache. /// - Task ClearAsync(); + Task ClearAsync(string homeAccountId); } } diff --git a/src/Microsoft.Identity.Web/TokenCacheProviders/MsalAbstractTokenCacheProvider.cs b/src/Microsoft.Identity.Web/TokenCacheProviders/MsalAbstractTokenCacheProvider.cs index 9013447cf..002bec830 100644 --- a/src/Microsoft.Identity.Web/TokenCacheProviders/MsalAbstractTokenCacheProvider.cs +++ b/src/Microsoft.Identity.Web/TokenCacheProviders/MsalAbstractTokenCacheProvider.cs @@ -2,7 +2,6 @@ // Licensed under the MIT License. using System; -using System.IdentityModel.Tokens.Jwt; using System.Threading.Tasks; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Options; @@ -54,26 +53,6 @@ public Task InitializeAsync(ITokenCache tokenCache) return Task.CompletedTask; } - /// - /// Cache key. - /// - private string GetCacheKey(bool isAppTokenCache) - { - if (isAppTokenCache) - { - return $"{_microsoftIdentityOptions.Value.ClientId}_AppTokenCache"; - } - else - { - // In the case of Web Apps, the cache key is the user account Id, and the expectation is that AcquireTokenSilent - // should return a token otherwise this might require a challenge. - // In the case Web APIs, the token cache key is a hash of the access token used to call the Web API - JwtSecurityToken jwtSecurityToken = _httpContextAccessor.HttpContext.GetTokenUsedToCallWebAPI(); - return (jwtSecurityToken != null) ? jwtSecurityToken.RawSignature - : _httpContextAccessor.HttpContext.User.GetMsalAccountId(); - } - } - /// /// Raised AFTER MSAL added the new token in its in-memory copy of the cache. /// This notification is called every time MSAL accesses the cache, not just when a write takes place: @@ -86,23 +65,14 @@ private async Task OnAfterAccessAsync(TokenCacheNotificationArgs args) // if the access operation resulted in a cache update if (args.HasStateChanged) { - string cacheKey = GetCacheKey(args.IsApplicationCache); - if (!string.IsNullOrWhiteSpace(cacheKey)) - { - await WriteCacheBytesAsync(cacheKey, args.TokenCache.SerializeMsalV3()).ConfigureAwait(false); - } + await WriteCacheBytesAsync(args.SuggestedCacheKey, args.TokenCache.SerializeMsalV3()).ConfigureAwait(false); } } private async Task OnBeforeAccessAsync(TokenCacheNotificationArgs args) { - string cacheKey = GetCacheKey(args.IsApplicationCache); - - if (!string.IsNullOrEmpty(cacheKey)) - { - byte[] tokenCacheBytes = await ReadCacheBytesAsync(cacheKey).ConfigureAwait(false); - args.TokenCache.DeserializeMsalV3(tokenCacheBytes, shouldClearExistingCache: true); - } + byte[] tokenCacheBytes = await ReadCacheBytesAsync(args.SuggestedCacheKey).ConfigureAwait(false); + args.TokenCache.DeserializeMsalV3(tokenCacheBytes, shouldClearExistingCache: true); } /// @@ -118,10 +88,11 @@ protected virtual Task OnBeforeWriteAsync(TokenCacheNotificationArgs args) /// /// Clear the cache. /// - public async Task ClearAsync() + /// HomeAccountId for a user account in the cache. + public async Task ClearAsync(string homeAccountId) { // This is a user token cache - await RemoveKeyAsync(GetCacheKey(false)).ConfigureAwait(false); + await RemoveKeyAsync(homeAccountId).ConfigureAwait(false); // TODO: Clear the cookie session if any. Get inspiration from // https://github.com/Azure-Samples/active-directory-aspnetcore-webapp-openidconnect-v2/issues/240 From c59315a455f86678fec84741b75b338f9d807740 Mon Sep 17 00:00:00 2001 From: Jenny Ferries Date: Wed, 1 Jul 2020 11:29:50 -0700 Subject: [PATCH 2/7] remove httpContext --- .../MsalDistributedTokenCacheAdapter.cs | 6 ---- .../InMemory/MsalMemoryTokenCacheProvider.cs | 5 --- .../MsalAbstractTokenCacheProvider.cs | 23 ------------- .../Session/MsalSessionTokenCacheProvider.cs | 33 +++++++++---------- 4 files changed, 15 insertions(+), 52 deletions(-) diff --git a/src/Microsoft.Identity.Web/TokenCacheProviders/Distributed/MsalDistributedTokenCacheAdapter.cs b/src/Microsoft.Identity.Web/TokenCacheProviders/Distributed/MsalDistributedTokenCacheAdapter.cs index dfc149dbe..4152d125f 100644 --- a/src/Microsoft.Identity.Web/TokenCacheProviders/Distributed/MsalDistributedTokenCacheAdapter.cs +++ b/src/Microsoft.Identity.Web/TokenCacheProviders/Distributed/MsalDistributedTokenCacheAdapter.cs @@ -2,7 +2,6 @@ // Licensed under the MIT License. using System.Threading.Tasks; -using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Caching.Distributed; using Microsoft.Extensions.Options; @@ -27,16 +26,11 @@ public class MsalDistributedTokenCacheAdapter : MsalAbstractTokenCacheProvider /// /// Initializes a new instance of the class. /// - /// - /// /// /// public MsalDistributedTokenCacheAdapter( - IOptions microsoftIdentityOptions, - IHttpContextAccessor httpContextAccessor, IDistributedCache memoryCache, IOptions cacheOptions) - : base(microsoftIdentityOptions, httpContextAccessor) { _distributedCache = memoryCache; _cacheOptions = cacheOptions.Value; diff --git a/src/Microsoft.Identity.Web/TokenCacheProviders/InMemory/MsalMemoryTokenCacheProvider.cs b/src/Microsoft.Identity.Web/TokenCacheProviders/InMemory/MsalMemoryTokenCacheProvider.cs index 061a19654..1f4f7c7aa 100644 --- a/src/Microsoft.Identity.Web/TokenCacheProviders/InMemory/MsalMemoryTokenCacheProvider.cs +++ b/src/Microsoft.Identity.Web/TokenCacheProviders/InMemory/MsalMemoryTokenCacheProvider.cs @@ -28,16 +28,11 @@ public class MsalMemoryTokenCacheProvider : MsalAbstractTokenCacheProvider /// /// Constructor. /// - /// Configuration options. - /// Accessor to the HttpContext. /// serialization cache. /// Memory cache options. public MsalMemoryTokenCacheProvider( - IOptions microsoftIdentityOptions, - IHttpContextAccessor httpContextAccessor, IMemoryCache memoryCache, IOptions cacheOptions) - : base(microsoftIdentityOptions, httpContextAccessor) { if (cacheOptions == null) { diff --git a/src/Microsoft.Identity.Web/TokenCacheProviders/MsalAbstractTokenCacheProvider.cs b/src/Microsoft.Identity.Web/TokenCacheProviders/MsalAbstractTokenCacheProvider.cs index 002bec830..fdc5082bd 100644 --- a/src/Microsoft.Identity.Web/TokenCacheProviders/MsalAbstractTokenCacheProvider.cs +++ b/src/Microsoft.Identity.Web/TokenCacheProviders/MsalAbstractTokenCacheProvider.cs @@ -3,8 +3,6 @@ using System; using System.Threading.Tasks; -using Microsoft.AspNetCore.Http; -using Microsoft.Extensions.Options; using Microsoft.Identity.Client; namespace Microsoft.Identity.Web.TokenCacheProviders @@ -13,27 +11,6 @@ namespace Microsoft.Identity.Web.TokenCacheProviders /// public abstract class MsalAbstractTokenCacheProvider : IMsalTokenCacheProvider { - /// - /// Azure AD options. - /// - protected readonly IOptions _microsoftIdentityOptions; - - /// - /// HTTP accessor. - /// - protected readonly IHttpContextAccessor _httpContextAccessor; - - /// - /// Constructor of the abstract token cache provider. - /// - /// Configuration options. - /// Accessor for the HttpContext. - protected MsalAbstractTokenCacheProvider(IOptions microsoftIdentityOptions, IHttpContextAccessor httpContextAccessor) - { - _microsoftIdentityOptions = microsoftIdentityOptions; - _httpContextAccessor = httpContextAccessor; - } - /// /// Initializes the token cache serialization. /// diff --git a/src/Microsoft.Identity.Web/TokenCacheProviders/Session/MsalSessionTokenCacheProvider.cs b/src/Microsoft.Identity.Web/TokenCacheProviders/Session/MsalSessionTokenCacheProvider.cs index 06cc6aaa7..40fa423be 100644 --- a/src/Microsoft.Identity.Web/TokenCacheProviders/Session/MsalSessionTokenCacheProvider.cs +++ b/src/Microsoft.Identity.Web/TokenCacheProviders/Session/MsalSessionTokenCacheProvider.cs @@ -5,7 +5,6 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Options; namespace Microsoft.Identity.Web.TokenCacheProviders.Session { @@ -31,21 +30,19 @@ namespace Microsoft.Identity.Web.TokenCacheProviders.Session /// https://aka.ms/msal-net-token-cache-serialization public class MsalSessionTokenCacheProvider : MsalAbstractTokenCacheProvider, IMsalTokenCacheProvider { - private HttpContext CurrentHttpContext => _httpContextAccessor.HttpContext; private ILogger _logger; + private ISession _session; /// /// MSAL Token cache provider constructor. /// - /// Configuration options. - /// accessor for an HttpContext. + /// Session for the current user. /// Logger. public MsalSessionTokenCacheProvider( - IOptions microsoftIdentityOptions, - IHttpContextAccessor httpContextAccessor, + ISession session, ILogger logger) - : base(microsoftIdentityOptions, httpContextAccessor) { + _session = session; _logger = logger; } @@ -57,18 +54,18 @@ public MsalSessionTokenCacheProvider( /// Read blob. protected override async Task ReadCacheBytesAsync(string cacheKey) { - await CurrentHttpContext.Session.LoadAsync().ConfigureAwait(false); + await _session.LoadAsync().ConfigureAwait(false); s_sessionLock.EnterReadLock(); try { - if (CurrentHttpContext.Session.TryGetValue(cacheKey, out byte[] blob)) + if (_session.TryGetValue(cacheKey, out byte[] blob)) { - _logger.LogInformation($"Deserializing session {CurrentHttpContext.Session.Id}, cacheId {cacheKey}"); + _logger.LogInformation($"Deserializing session {_session.Id}, cacheId {cacheKey}"); } else { - _logger.LogInformation($"CacheId {cacheKey} not found in session {CurrentHttpContext.Session.Id}"); + _logger.LogInformation($"CacheId {cacheKey} not found in session {_session.Id}"); } return blob; @@ -89,11 +86,11 @@ protected override async Task WriteCacheBytesAsync(string cacheKey, byte[] bytes s_sessionLock.EnterWriteLock(); try { - _logger.LogInformation($"Serializing session {CurrentHttpContext.Session.Id}, cacheId {cacheKey}"); + _logger.LogInformation($"Serializing session {_session.Id}, cacheId {cacheKey}"); // Reflect changes in the persistent store - CurrentHttpContext.Session.Set(cacheKey, bytes); - await CurrentHttpContext.Session.CommitAsync().ConfigureAwait(false); + _session.Set(cacheKey, bytes); + await _session.CommitAsync().ConfigureAwait(false); } finally { @@ -104,17 +101,17 @@ protected override async Task WriteCacheBytesAsync(string cacheKey, byte[] bytes /// /// Removes a cache described from its key. /// - /// key of the token cache (user account or app ID). + /// Key of the token cache (user account or app ID). protected override async Task RemoveKeyAsync(string cacheKey) { s_sessionLock.EnterWriteLock(); try { - _logger.LogInformation($"Clearing session {CurrentHttpContext.Session.Id}, cacheId {cacheKey}"); + _logger.LogInformation($"Clearing session {_session.Id}, cacheId {cacheKey}"); // Reflect changes in the persistent store - CurrentHttpContext.Session.Remove(cacheKey); - await CurrentHttpContext.Session.CommitAsync().ConfigureAwait(false); + _session.Remove(cacheKey); + await _session.CommitAsync().ConfigureAwait(false); } finally { From aa279cafeeae630360a95393cfc798f40457b559 Mon Sep 17 00:00:00 2001 From: Jenny Ferries Date: Wed, 1 Jul 2020 12:24:37 -0700 Subject: [PATCH 3/7] merge conflicts --- .../Microsoft.Identity.Web.xml | 48 ++++--------------- .../TokenAcquisition.cs | 39 ++++++++------- .../MsalDistributedTokenCacheAdapter.cs | 2 +- .../IMsalTokenCacheProvider.cs | 1 - .../TestHelpers/MsalTestTokenCacheProvider.cs | 3 -- .../AcquireTokenForAppIntegrationTests.cs | 2 - 6 files changed, 33 insertions(+), 62 deletions(-) diff --git a/src/Microsoft.Identity.Web/Microsoft.Identity.Web.xml b/src/Microsoft.Identity.Web/Microsoft.Identity.Web.xml index b8e22880c..d722e01db 100644 --- a/src/Microsoft.Identity.Web/Microsoft.Identity.Web.xml +++ b/src/Microsoft.Identity.Web/Microsoft.Identity.Web.xml @@ -1207,8 +1207,8 @@ - When applied to an , verifies that the application in the - web API has the expected roles. + When applied to an , verifies that the application + has the expected roles. HttpContext (from the controller). Roles accepted by this web API. @@ -1456,12 +1456,10 @@ MSAL memory token cache options. - + Initializes a new instance of the class. - - @@ -1507,11 +1505,11 @@ Token cache for which to initialize the serialization. A that represents a completed initialization operation. - + Clear the cache. - A that represents a completed clear operation. + HomeAccountId for a user account in the cache. @@ -1558,12 +1556,10 @@ MSAL memory token cache options. - + Constructor. - Configuration options. - Accessor to the HttpContext. serialization cache. Memory cache options. @@ -1594,23 +1590,6 @@ - - - Azure AD options. - - - - - HTTP accessor. - - - - - Constructor of the abstract token cache provider. - - Configuration options. - Accessor for the HttpContext. - Initializes the token cache serialization. @@ -1618,12 +1597,6 @@ Token cache to serialize/deserialize. A that represents a completed initialization operation. - - - Cache key. - - The cache key. - Raised AFTER MSAL added the new token in its in-memory copy of the cache. @@ -1640,11 +1613,11 @@ Token cache notification arguments. A that represents a completed operation. - + Clear the cache. - A that represents a completed clear operation. + HomeAccountId for a user account in the cache. @@ -1690,12 +1663,11 @@ https://aka.ms/msal-net-token-cache-serialization - + MSAL Token cache provider constructor. - Configuration options. - Accessor for an HttpContext. + Session for the current user. Logger. diff --git a/src/Microsoft.Identity.Web/TokenAcquisition.cs b/src/Microsoft.Identity.Web/TokenAcquisition.cs index 1fd89d01a..8343b2304 100644 --- a/src/Microsoft.Identity.Web/TokenAcquisition.cs +++ b/src/Microsoft.Identity.Web/TokenAcquisition.cs @@ -283,29 +283,34 @@ public async Task GetAccessTokenForAppAsync(IEnumerable scopes) /// A that represents a completed account removal operation. public async Task RemoveAccountAsync(RedirectContext context) { - IConfidentialClientApplication app = await GetOrBuildConfidentialClientApplicationAsync().ConfigureAwait(false); - - // For B2C, we should remove all accounts of the user regardless the user flow - if (_microsoftIdentityOptions.IsB2C) + ClaimsPrincipal user = context.HttpContext.User; + string? userId = user.GetMsalAccountId(); + if (!string.IsNullOrEmpty(userId)) { - var b2cAccounts = await app.GetAccountsAsync().ConfigureAwait(false); + IConfidentialClientApplication app = await GetOrBuildConfidentialClientApplicationAsync().ConfigureAwait(false); - foreach (var b2cAccount in b2cAccounts) + // For B2C, we should remove all accounts of the user regardless the user flow + if (_microsoftIdentityOptions.IsB2C) { - await app.RemoveAsync(b2cAccount).ConfigureAwait(false); - } + var b2cAccounts = await app.GetAccountsAsync().ConfigureAwait(false); - _tokenCacheProvider?.ClearAsync(user.GetMsalAccountId()).ConfigureAwait(false); - } - else - { - string? identifier = context.HttpContext.User.GetMsalAccountId(); - IAccount account = await app.GetAccountAsync(identifier).ConfigureAwait(false); + foreach (var b2cAccount in b2cAccounts) + { + await app.RemoveAsync(b2cAccount).ConfigureAwait(false); + } - if (account != null) + _tokenCacheProvider?.ClearAsync(userId).ConfigureAwait(false); + } + else { - await app.RemoveAsync(account).ConfigureAwait(false); - _tokenCacheProvider?.ClearAsync(user.GetMsalAccountId()).ConfigureAwait(false); + string? identifier = context.HttpContext.User.GetMsalAccountId(); + IAccount account = await app.GetAccountAsync(identifier).ConfigureAwait(false); + + if (account != null) + { + await app.RemoveAsync(account).ConfigureAwait(false); + _tokenCacheProvider?.ClearAsync(userId).ConfigureAwait(false); + } } } } diff --git a/src/Microsoft.Identity.Web/TokenCacheProviders/Distributed/MsalDistributedTokenCacheAdapter.cs b/src/Microsoft.Identity.Web/TokenCacheProviders/Distributed/MsalDistributedTokenCacheAdapter.cs index f8c22cbc1..09d733bf8 100644 --- a/src/Microsoft.Identity.Web/TokenCacheProviders/Distributed/MsalDistributedTokenCacheAdapter.cs +++ b/src/Microsoft.Identity.Web/TokenCacheProviders/Distributed/MsalDistributedTokenCacheAdapter.cs @@ -39,7 +39,7 @@ public MsalDistributedTokenCacheAdapter( } _distributedCache = memoryCache; - _cacheOptions = cacheOptions.Value; + _cacheOptions = (MsalDistributedTokenCacheAdapterOptions)cacheOptions.Value; } /// diff --git a/src/Microsoft.Identity.Web/TokenCacheProviders/IMsalTokenCacheProvider.cs b/src/Microsoft.Identity.Web/TokenCacheProviders/IMsalTokenCacheProvider.cs index 00ff3941b..b41f14a59 100644 --- a/src/Microsoft.Identity.Web/TokenCacheProviders/IMsalTokenCacheProvider.cs +++ b/src/Microsoft.Identity.Web/TokenCacheProviders/IMsalTokenCacheProvider.cs @@ -22,7 +22,6 @@ public interface IMsalTokenCacheProvider /// Clear the cache. /// /// HomeAccountId for a user account in the cache. - /// Task ClearAsync(string homeAccountId); } } diff --git a/tests/Microsoft.Identity.Web.Test.Common/TestHelpers/MsalTestTokenCacheProvider.cs b/tests/Microsoft.Identity.Web.Test.Common/TestHelpers/MsalTestTokenCacheProvider.cs index babe901db..aed2e2e47 100644 --- a/tests/Microsoft.Identity.Web.Test.Common/TestHelpers/MsalTestTokenCacheProvider.cs +++ b/tests/Microsoft.Identity.Web.Test.Common/TestHelpers/MsalTestTokenCacheProvider.cs @@ -13,11 +13,8 @@ namespace Microsoft.Identity.Web.Test.Common.TestHelpers public class MsalTestTokenCacheProvider : MsalAbstractTokenCacheProvider { public MsalTestTokenCacheProvider( - IOptions microsoftIdentityOptions, - IHttpContextAccessor httpContextAccessor, IMemoryCache memoryCache, IOptions cacheOptions) - : base(microsoftIdentityOptions, httpContextAccessor) { MemoryCache = memoryCache; _cacheOptions = cacheOptions?.Value; diff --git a/tests/Microsoft.Identity.Web.Test.Integration/AcquireTokenForAppIntegrationTests.cs b/tests/Microsoft.Identity.Web.Test.Integration/AcquireTokenForAppIntegrationTests.cs index 13b0d8868..6486d3188 100644 --- a/tests/Microsoft.Identity.Web.Test.Integration/AcquireTokenForAppIntegrationTests.cs +++ b/tests/Microsoft.Identity.Web.Test.Integration/AcquireTokenForAppIntegrationTests.cs @@ -98,8 +98,6 @@ private void InitializeTokenAcquisitionObjects() IHttpContextAccessor httpContextAccessor = CreateMockHttpContextAccessor(); _msalTestTokenCacheProvider = new MsalTestTokenCacheProvider( - microsoftIdentityOptions, - httpContextAccessor, _provider.GetService(), tokenOptions); From e1c1281a995e177a333eb0d146960a10a9360bf7 Mon Sep 17 00:00:00 2001 From: Jean-Marc Prieur Date: Tue, 7 Jul 2020 15:38:29 +0200 Subject: [PATCH 4/7] Updating the version of MSA.NET as the NuGet package was just published --- src/Microsoft.Identity.Web/Microsoft.Identity.Web.csproj | 2 +- .../Microsoft.Identity.Web.Test.LabInfrastructure.csproj | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Microsoft.Identity.Web/Microsoft.Identity.Web.csproj b/src/Microsoft.Identity.Web/Microsoft.Identity.Web.csproj index f95c2a052..bf5223ffa 100644 --- a/src/Microsoft.Identity.Web/Microsoft.Identity.Web.csproj +++ b/src/Microsoft.Identity.Web/Microsoft.Identity.Web.csproj @@ -88,7 +88,7 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/tests/Microsoft.Identity.Web.Test.LabInfrastructure/Microsoft.Identity.Web.Test.LabInfrastructure.csproj b/tests/Microsoft.Identity.Web.Test.LabInfrastructure/Microsoft.Identity.Web.Test.LabInfrastructure.csproj index 8a7a2cc2f..4aacde9c0 100644 --- a/tests/Microsoft.Identity.Web.Test.LabInfrastructure/Microsoft.Identity.Web.Test.LabInfrastructure.csproj +++ b/tests/Microsoft.Identity.Web.Test.LabInfrastructure/Microsoft.Identity.Web.Test.LabInfrastructure.csproj @@ -17,7 +17,7 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive - + all runtime; build; native; contentfiles; analyzers; buildtransitive From 008e8b4686d9cd4e1a3506153bc898d84b3ddb06 Mon Sep 17 00:00:00 2001 From: Jean-Marc Prieur Date: Tue, 7 Jul 2020 17:17:17 +0200 Subject: [PATCH 5/7] =?UTF-8?q?This=20is=20an=20improvement=20leveraging?= =?UTF-8?q?=20the=20fact=20that=20MSAL.NET=20now=20exposes=20=E2=80=A6=20(?= =?UTF-8?q?#294)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * This is an improvement leveraging the fact that MSAL.NET now exposes TokenCacheNotificationArgs.HasTokens which enable applications (and Microsoft.Identity.Web) to remove cache entries when the cache is empty Also OnBeforeAccessAsync tests if the SuggestedCacheKey is null (can happen in B2C cases, as we still call GetAccountsAsync() * Removing the un-necessary condition on suggested cache key (which should not be null in a Write to cache) It can be null in a read to cache if for instance, calling GetAccountsAsync() * Removing an extra line * remove secret Co-authored-by: jennyf19 --- .../MsalAbstractTokenCacheProvider.cs | 19 ++++++++++++---- .../Client/appsettings.json | 22 +++++++++---------- 2 files changed, 26 insertions(+), 15 deletions(-) diff --git a/src/Microsoft.Identity.Web/TokenCacheProviders/MsalAbstractTokenCacheProvider.cs b/src/Microsoft.Identity.Web/TokenCacheProviders/MsalAbstractTokenCacheProvider.cs index 1dd75b995..69bb28e6b 100644 --- a/src/Microsoft.Identity.Web/TokenCacheProviders/MsalAbstractTokenCacheProvider.cs +++ b/src/Microsoft.Identity.Web/TokenCacheProviders/MsalAbstractTokenCacheProvider.cs @@ -41,17 +41,28 @@ public Task InitializeAsync(ITokenCache tokenCache) /// Contains parameters used by the MSAL call accessing the cache. private async Task OnAfterAccessAsync(TokenCacheNotificationArgs args) { - // if the access operation resulted in a cache update + // The access operation resulted in a cache update. if (args.HasStateChanged) { - await WriteCacheBytesAsync(args.SuggestedCacheKey, args.TokenCache.SerializeMsalV3()).ConfigureAwait(false); + if (args.HasTokens) + { + await WriteCacheBytesAsync(args.SuggestedCacheKey, args.TokenCache.SerializeMsalV3()).ConfigureAwait(false); + } + else + { + // No token in the cache. we can remove the cache entry + await RemoveKeyAsync(args.SuggestedCacheKey).ConfigureAwait(false); + } } } private async Task OnBeforeAccessAsync(TokenCacheNotificationArgs args) { - byte[] tokenCacheBytes = await ReadCacheBytesAsync(args.SuggestedCacheKey).ConfigureAwait(false); - args.TokenCache.DeserializeMsalV3(tokenCacheBytes, shouldClearExistingCache: true); + if (!string.IsNullOrEmpty(args.SuggestedCacheKey)) + { + byte[] tokenCacheBytes = await ReadCacheBytesAsync(args.SuggestedCacheKey).ConfigureAwait(false); + args.TokenCache.DeserializeMsalV3(tokenCacheBytes, shouldClearExistingCache: true); + } } /// diff --git a/tests/B2CWebAppCallsWebApi/Client/appsettings.json b/tests/B2CWebAppCallsWebApi/Client/appsettings.json index 093940003..12e5052a8 100644 --- a/tests/B2CWebAppCallsWebApi/Client/appsettings.json +++ b/tests/B2CWebAppCallsWebApi/Client/appsettings.json @@ -1,15 +1,15 @@ { - "AzureAdB2C": { - "Instance": "https://fabrikamb2c.b2clogin.com", - "ClientId": "fdb91ff5-5ce6-41f3-bdbd-8267c817015d", - "Domain": "fabrikamb2c.onmicrosoft.com", - "SignedOutCallbackPath": "/signout/B2C_1_susi", - "SignUpSignInPolicyId": "b2c_1_susi", - "ResetPasswordPolicyId": "b2c_1_reset", - "EditProfilePolicyId": "b2c_1_edit_profile", // Optional profile editing policy - "ClientSecret": "[Copy the client secret added to the app from the Azure portal]" - //"CallbackPath": "/signin/B2C_1_sign_up_in" // defaults to /signin-oidc - }, + "AzureAdB2C": { + "Instance": "https://fabrikamb2c.b2clogin.com", + "ClientId": "fdb91ff5-5ce6-41f3-bdbd-8267c817015d", + "Domain": "fabrikamb2c.onmicrosoft.com", + "SignedOutCallbackPath": "/signout/B2C_1_susi", + "SignUpSignInPolicyId": "b2c_1_susi", + "ResetPasswordPolicyId": "b2c_1_reset", + "EditProfilePolicyId": "b2c_1_edit_profile", // Optional profile editing policy + "ClientSecret": "[Copy the client secret added to the app from the Azure portal]" + //"CallbackPath": "/signin/B2C_1_sign_up_in" // defaults to /signin-oidc + }, "TodoList": { /* TodoListScope is the scope of the Web API you want to call. This can be: "api://8f085429-c424-45c4-beb3-75f6f0a7924f/user_impersonation", From b2b9d4125b05eb4bb86bbbfd762bdce91d11c740 Mon Sep 17 00:00:00 2001 From: Jenny Ferries Date: Tue, 7 Jul 2020 08:32:41 -0700 Subject: [PATCH 6/7] pr feedback --- src/Microsoft.Identity.Web/TokenAcquisition.cs | 4 ++-- .../Distributed/MsalDistributedTokenCacheAdapter.cs | 2 +- .../TokenCacheProviders/IMsalTokenCacheProvider.cs | 3 ++- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/Microsoft.Identity.Web/TokenAcquisition.cs b/src/Microsoft.Identity.Web/TokenAcquisition.cs index 1e561e824..75c91831d 100644 --- a/src/Microsoft.Identity.Web/TokenAcquisition.cs +++ b/src/Microsoft.Identity.Web/TokenAcquisition.cs @@ -299,7 +299,7 @@ public async Task RemoveAccountAsync(RedirectContext context) await app.RemoveAsync(b2cAccount).ConfigureAwait(false); } - _tokenCacheProvider?.ClearAsync(userId).ConfigureAwait(false); + await _tokenCacheProvider.ClearAsync(userId).ConfigureAwait(false); } else { @@ -309,7 +309,7 @@ public async Task RemoveAccountAsync(RedirectContext context) if (account != null) { await app.RemoveAsync(account).ConfigureAwait(false); - _tokenCacheProvider?.ClearAsync(userId).ConfigureAwait(false); + await _tokenCacheProvider.ClearAsync(userId).ConfigureAwait(false); } } } diff --git a/src/Microsoft.Identity.Web/TokenCacheProviders/Distributed/MsalDistributedTokenCacheAdapter.cs b/src/Microsoft.Identity.Web/TokenCacheProviders/Distributed/MsalDistributedTokenCacheAdapter.cs index 09d733bf8..04ec6d5c7 100644 --- a/src/Microsoft.Identity.Web/TokenCacheProviders/Distributed/MsalDistributedTokenCacheAdapter.cs +++ b/src/Microsoft.Identity.Web/TokenCacheProviders/Distributed/MsalDistributedTokenCacheAdapter.cs @@ -31,7 +31,7 @@ public class MsalDistributedTokenCacheAdapter : MsalAbstractTokenCacheProvider /// public MsalDistributedTokenCacheAdapter( IDistributedCache memoryCache, - IOptions cacheOptions) + IOptions cacheOptions) { if (cacheOptions == null) { diff --git a/src/Microsoft.Identity.Web/TokenCacheProviders/IMsalTokenCacheProvider.cs b/src/Microsoft.Identity.Web/TokenCacheProviders/IMsalTokenCacheProvider.cs index b41f14a59..bf85a894a 100644 --- a/src/Microsoft.Identity.Web/TokenCacheProviders/IMsalTokenCacheProvider.cs +++ b/src/Microsoft.Identity.Web/TokenCacheProviders/IMsalTokenCacheProvider.cs @@ -19,9 +19,10 @@ public interface IMsalTokenCacheProvider Task InitializeAsync(ITokenCache tokenCache); /// - /// Clear the cache. + /// Clear the user token cache. /// /// HomeAccountId for a user account in the cache. + /// A that represents a completed clear operation. Task ClearAsync(string homeAccountId); } } From 9deb3269d0f7c8c11a4becc4d605bc89c9b60490 Mon Sep 17 00:00:00 2001 From: Jenny Ferries Date: Tue, 7 Jul 2020 10:53:33 -0700 Subject: [PATCH 7/7] remove cast --- .../Distributed/MsalDistributedTokenCacheAdapter.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Microsoft.Identity.Web/TokenCacheProviders/Distributed/MsalDistributedTokenCacheAdapter.cs b/src/Microsoft.Identity.Web/TokenCacheProviders/Distributed/MsalDistributedTokenCacheAdapter.cs index 04ec6d5c7..866c46cad 100644 --- a/src/Microsoft.Identity.Web/TokenCacheProviders/Distributed/MsalDistributedTokenCacheAdapter.cs +++ b/src/Microsoft.Identity.Web/TokenCacheProviders/Distributed/MsalDistributedTokenCacheAdapter.cs @@ -39,7 +39,7 @@ public MsalDistributedTokenCacheAdapter( } _distributedCache = memoryCache; - _cacheOptions = (MsalDistributedTokenCacheAdapterOptions)cacheOptions.Value; + _cacheOptions = cacheOptions.Value; } ///