-
Notifications
You must be signed in to change notification settings - Fork 218
/
MsalSessionTokenCacheProvider.cs
127 lines (116 loc) · 4.93 KB
/
MsalSessionTokenCacheProvider.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
namespace Microsoft.Identity.Web.TokenCacheProviders.Session
{
/// <summary>
/// An implementation of token cache for confidential clients backed by an HTTP session.
/// </summary>
/// <remarks>
/// For this session cache to work effectively the ASP.NET Core session has to be configured properly.
/// The latest guidance is provided at https://docs.microsoft.com/aspnet/core/fundamentals/app-state
///
/// In the method <c>public void ConfigureServices(IServiceCollection services)</c> in Startup.cs, add the following:
/// <code>
/// services.AddSession(option =>
/// {
/// option.Cookie.IsEssential = true;
/// });
/// </code>
/// In the method <c>public void Configure(IApplicationBuilder app, IHostingEnvironment env)</c> in Startup.cs, add the following:
/// <code>
/// app.UseSession(); // Before UseMvc()
/// </code>
/// </remarks>
/// <seealso>https://aka.ms/msal-net-token-cache-serialization</seealso>
public class MsalSessionTokenCacheProvider : MsalAbstractTokenCacheProvider, IMsalTokenCacheProvider
{
private HttpContext CurrentHttpContext => _httpContextAccessor.HttpContext;
private ILogger _logger;
/// <summary>
/// MSAL Token cache provider constructor.
/// </summary>
/// <param name="microsoftIdentityOptions">Configuration options.</param>
/// <param name="httpContextAccessor">accessor for an HttpContext.</param>
/// <param name="logger">Logger.</param>
public MsalSessionTokenCacheProvider(
IOptions<MicrosoftIdentityOptions> microsoftIdentityOptions,
IHttpContextAccessor httpContextAccessor,
ILogger<MsalSessionTokenCacheProvider> logger)
: base(microsoftIdentityOptions, httpContextAccessor)
{
_logger = logger;
}
/// <summary>
/// Read a blob representing the token cache from its key.
/// </summary>
/// <param name="cacheKey">Key representing the token cache
/// (account or app).</param>
/// <returns>Read blob.</returns>
protected override async Task<byte[]> ReadCacheBytesAsync(string cacheKey)
{
await CurrentHttpContext.Session.LoadAsync().ConfigureAwait(false);
s_sessionLock.EnterReadLock();
try
{
if (CurrentHttpContext.Session.TryGetValue(cacheKey, out byte[] blob))
{
_logger.LogInformation($"Deserializing session {CurrentHttpContext.Session.Id}, cacheId {cacheKey}");
}
else
{
_logger.LogInformation($"CacheId {cacheKey} not found in session {CurrentHttpContext.Session.Id}");
}
return blob;
}
finally
{
s_sessionLock.ExitReadLock();
}
}
/// <summary>
/// Writes the token cache identified by its key to the serialization mechanism.
/// </summary>
/// <param name="cacheKey">key for the cache (account ID or app ID).</param>
/// <param name="bytes">blob to write to the cache.</param>
protected override async Task WriteCacheBytesAsync(string cacheKey, byte[] bytes)
{
s_sessionLock.EnterWriteLock();
try
{
_logger.LogInformation($"Serializing session {CurrentHttpContext.Session.Id}, cacheId {cacheKey}");
// Reflect changes in the persistent store
CurrentHttpContext.Session.Set(cacheKey, bytes);
await CurrentHttpContext.Session.CommitAsync().ConfigureAwait(false);
}
finally
{
s_sessionLock.ExitWriteLock();
}
}
/// <summary>
/// Removes a cache described from its key.
/// </summary>
/// <param name="cacheKey">key of the token cache (user account or app ID).</param>
protected override async Task RemoveKeyAsync(string cacheKey)
{
s_sessionLock.EnterWriteLock();
try
{
_logger.LogInformation($"Clearing session {CurrentHttpContext.Session.Id}, cacheId {cacheKey}");
// Reflect changes in the persistent store
CurrentHttpContext.Session.Remove(cacheKey);
await CurrentHttpContext.Session.CommitAsync().ConfigureAwait(false);
}
finally
{
s_sessionLock.ExitWriteLock();
}
}
private static readonly ReaderWriterLockSlim s_sessionLock = new ReaderWriterLockSlim(LockRecursionPolicy.NoRecursion);
}
}