diff --git a/TaskWebApp/TaskWebApp.csproj b/TaskWebApp/TaskWebApp.csproj index 1573c5b..49f2b86 100644 --- a/TaskWebApp/TaskWebApp.csproj +++ b/TaskWebApp/TaskWebApp.csproj @@ -52,8 +52,8 @@ ..\packages\Antlr.3.5.0.2\lib\Antlr3.Runtime.dll - - ..\packages\Microsoft.Identity.Client.3.0.8\lib\net45\Microsoft.Identity.Client.dll + + ..\packages\Microsoft.Identity.Client.4.3.1\lib\net45\Microsoft.Identity.Client.dll ..\packages\Microsoft.IdentityModel.JsonWebTokens.5.4.0\lib\net451\Microsoft.IdentityModel.JsonWebTokens.dll @@ -187,7 +187,6 @@ - diff --git a/TaskWebApp/Utils/MSALPerUserMemoryTokenCache.cs b/TaskWebApp/Utils/MSALPerUserMemoryTokenCache.cs index 3624b51..7784f0a 100644 --- a/TaskWebApp/Utils/MSALPerUserMemoryTokenCache.cs +++ b/TaskWebApp/Utils/MSALPerUserMemoryTokenCache.cs @@ -41,11 +41,6 @@ public class MSALPerUserMemoryTokenCache /// private readonly DateTimeOffset cacheDuration = DateTimeOffset.Now.AddHours(48); - /// - /// The internal handle to the client's instance of the Cache - /// - private ITokenCache UserTokenCache; - /// /// Once the user signes in, this will not be null and can be ontained via a call to Thread.CurrentPrincipal /// @@ -77,18 +72,15 @@ private void Initialize(ITokenCache tokenCache, ClaimsPrincipal user) { this.SignedInUser = user; - this.UserTokenCache = tokenCache; - this.UserTokenCache.SetBeforeAccess(this.UserTokenCacheBeforeAccessNotification); - this.UserTokenCache.SetAfterAccess(this.UserTokenCacheAfterAccessNotification); - this.UserTokenCache.SetBeforeWrite(this.UserTokenCacheBeforeWriteNotification); + tokenCache.SetBeforeAccess(this.UserTokenCacheBeforeAccessNotification); + tokenCache.SetAfterAccess(this.UserTokenCacheAfterAccessNotification); + tokenCache.SetBeforeWrite(this.UserTokenCacheBeforeWriteNotification); if (this.SignedInUser == null) { // No users signed in yet, so we return return; } - - this.LoadUserTokenCacheFromMemory(); } /// @@ -107,7 +99,7 @@ internal string GetMsalAccountId() /// /// Loads the user token cache from memory. /// - private void LoadUserTokenCacheFromMemory() + private void LoadUserTokenCacheFromMemory(ITokenCacheSerializer tokenCache) { string cacheKey = this.GetMsalAccountId(); @@ -116,13 +108,13 @@ private void LoadUserTokenCacheFromMemory() // Ideally, methods that load and persist should be thread safe. MemoryCache.Get() is thread safe. byte[] tokenCacheBytes = (byte[])this.memoryCache.Get(this.GetMsalAccountId()); - this.UserTokenCache.DeserializeMsalV3(tokenCacheBytes); + tokenCache.DeserializeMsalV3(tokenCacheBytes); } /// /// Persists the user token blob to the memoryCache. /// - private void PersistUserTokenCache() + private void PersistUserTokenCache(ITokenCacheSerializer tokenCache) { string cacheKey = this.GetMsalAccountId(); @@ -130,7 +122,7 @@ private void PersistUserTokenCache() return; // Ideally, methods that load and persist should be thread safe.MemoryCache.Get() is thread safe. - this.memoryCache.Set(this.GetMsalAccountId(), this.UserTokenCache.SerializeMsalV3(), this.cacheDuration); + this.memoryCache.Set(this.GetMsalAccountId(), tokenCache.SerializeMsalV3(), this.cacheDuration); } /// @@ -139,9 +131,6 @@ private void PersistUserTokenCache() public void Clear() { this.memoryCache.Remove(this.GetMsalAccountId()); - - // Nulls the currently deserialized instance - this.LoadUserTokenCacheFromMemory(); } /// @@ -155,7 +144,7 @@ private void UserTokenCacheAfterAccessNotification(TokenCacheNotificationArgs ar // if the access operation resulted in a cache update if (args.HasStateChanged) { - this.PersistUserTokenCache(); + this.PersistUserTokenCache(args.TokenCache); } } @@ -165,7 +154,7 @@ private void UserTokenCacheAfterAccessNotification(TokenCacheNotificationArgs ar /// Contains parameters used by the MSAL call accessing the cache. private void UserTokenCacheBeforeAccessNotification(TokenCacheNotificationArgs args) { - this.LoadUserTokenCacheFromMemory(); + this.LoadUserTokenCacheFromMemory(args.TokenCache); } /// diff --git a/TaskWebApp/Utils/MSALPerUserSessionTokenCache.cs b/TaskWebApp/Utils/MSALPerUserSessionTokenCache.cs deleted file mode 100644 index c4dc1ce..0000000 --- a/TaskWebApp/Utils/MSALPerUserSessionTokenCache.cs +++ /dev/null @@ -1,210 +0,0 @@ -/* - The MIT License (MIT) - -Copyright (c) 2015 Microsoft Corporation - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. -*/ - -using Microsoft.Identity.Client; -using System.Security.Claims; -using System.Threading; -using System.Web; - -namespace TaskWebApp.Utils -{ - /// - /// This is a MSAL's TokenCache implementation for one user. It uses Sql server as a backend store and uses the Entity Framework to read and write to that database. - /// - /// - public class MSALPerUserSessionTokenCache - { - private static ReaderWriterLockSlim SessionLock = new ReaderWriterLockSlim(LockRecursionPolicy.NoRecursion); - - /// - /// Once the user signes in, this will not be null and can be ontained via a call to ClaimsPrincipal.Current - /// - internal ClaimsPrincipal SignedInUser; - - /// - /// The HTTP context being used by this app - /// - private HttpContextBase HttpContext = null; - - /// - /// The internal handle to the client's instance of the Cache - /// - private ITokenCache UserTokenCache; - - /// Initializes a new instance of the class. - /// The token cache. - /// The current HttpContext. - public MSALPerUserSessionTokenCache(ITokenCache tokenCache, HttpContextBase httpcontext) - { - this.Initialize(tokenCache, httpcontext, ClaimsPrincipal.Current); - } - - public MSALPerUserSessionTokenCache(ITokenCache tokenCache, HttpContextBase httpcontext, ClaimsPrincipal user) - { - this.Initialize(tokenCache, httpcontext, user); - } - - /// Initializes the cache instance - /// The ITokenCache passed through the constructor - /// The current HttpContext - /// The signed in user's ClaimPrincipal, could be null. - /// If the calling app has it available, then it should pass it themselves. - private void Initialize(ITokenCache tokenCache, HttpContextBase httpcontext, ClaimsPrincipal user) - { - this.HttpContext = httpcontext; - - this.UserTokenCache = tokenCache; - - this.UserTokenCache.SetBeforeAccess(this.UserTokenCacheBeforeAccessNotification); - this.UserTokenCache.SetAfterAccess(this.UserTokenCacheAfterAccessNotification); - this.UserTokenCache.SetBeforeWrite(this.UserTokenCacheBeforeWriteNotification); - - if (user == null) - { - // No users signed in yet, so we return - return; - } - - this.SignedInUser = user; - this.LoadUserTokenCacheFromSession(); - } - - /// - /// Loads the user token cache from http session. - /// - public void LoadUserTokenCacheFromSession() - { - string cacheKey = this.GetSignedInUsersUniqueId(); - - if (string.IsNullOrWhiteSpace(cacheKey)) - return; - - SessionLock.EnterReadLock(); - try - { - this.UserTokenCache.DeserializeMsalV3((byte[])this.HttpContext.Session[cacheKey]); - } - finally - { - SessionLock.ExitReadLock(); - } - } - - /// - /// Persists the user token blob to the Http session. - /// - public void PersistUserTokenCache() - { - string cacheKey = this.GetSignedInUsersUniqueId(); - - if (string.IsNullOrWhiteSpace(cacheKey)) - return; - - SessionLock.EnterWriteLock(); - - try - { - // Reflect changes in the persistence store - this.HttpContext.Session[cacheKey] = this.UserTokenCache.SerializeMsalV3(); - } - finally - { - SessionLock.ExitWriteLock(); - } - } - - /// - /// Clears the TokenCache's copy of this user's cache. - /// - public void Clear() - { - string cacheKey = this.GetSignedInUsersUniqueId(); - - if (string.IsNullOrWhiteSpace(cacheKey)) - return; - - // httpContext.Session[this.GetSignedInUsersCacheKey()] = null; - - SessionLock.EnterWriteLock(); - - try - { - // Reflect changes in the persistent store - this.HttpContext.Session.Remove(cacheKey); - } - finally - { - SessionLock.ExitWriteLock(); - } - - // Nulls the currently deserialized instance - this.LoadUserTokenCacheFromSession(); - } - - /// - /// if you want to ensure that no concurrent write take place, use this notification to place a lock on the entry - /// - /// Contains parameters used by the MSAL call accessing the cache. - - private void UserTokenCacheBeforeWriteNotification(TokenCacheNotificationArgs args) - { - // Since we obtain and release lock right before and after we read the Http session, we need not do anything here. - } - - /// - /// Triggered right after MSAL accessed the cache. - /// - /// Contains parameters used by the MSAL call accessing the cache. - private void UserTokenCacheAfterAccessNotification(TokenCacheNotificationArgs args) - { - // if the access operation resulted in a cache update - if (args.HasStateChanged) - { - this.PersistUserTokenCache(); - } - } - - /// - /// Triggered right before MSAL needs to access the cache. Reload the cache from the persistence store in case it changed since the last access. - /// - /// Contains parameters used by the MSAL call accessing the cache. - private void UserTokenCacheBeforeAccessNotification(TokenCacheNotificationArgs args) - { - this.LoadUserTokenCacheFromSession(); - } - - /// - /// Explores the Claims of a signed-in user (if available) to populate the unique Id of this cache's instance. - /// - /// The signed in user's object.tenant Id , if available in the ClaimsPrincipal.Current instance - internal string GetSignedInUsersUniqueId() - { - if (this.SignedInUser != null) - { - return this.SignedInUser.GetB2CMsalAccountId(); - } - return null; - } - } -} \ No newline at end of file diff --git a/TaskWebApp/Utils/MsalAppBuilder.cs b/TaskWebApp/Utils/MsalAppBuilder.cs index 11e2a7a..d6ace6d 100644 --- a/TaskWebApp/Utils/MsalAppBuilder.cs +++ b/TaskWebApp/Utils/MsalAppBuilder.cs @@ -76,8 +76,8 @@ public static async Task ClearUserTokenCache() //Remove the users from the MSAL's internal cache await clientapp.RemoveAsync(account); } + userTokenCache.Clear(); - userTokenCache.Clear(); - } - } + } + } } \ No newline at end of file diff --git a/TaskWebApp/packages.config b/TaskWebApp/packages.config index 7c67a14..8ea9241 100644 --- a/TaskWebApp/packages.config +++ b/TaskWebApp/packages.config @@ -9,7 +9,7 @@ - +