Skip to content
Merged
Original file line number Diff line number Diff line change
Expand Up @@ -27,5 +27,10 @@ public class CacheSerializerHints
/// Stores details to log to MSAL's telemetry client
/// </summary>
internal TelemetryData? TelemetryData { get; set; }

/// <summary>
/// Error message to display in the cases where the client application should not use the distributed cache (not null or empty means it shouldn't use it)
/// </summary>
internal string? ShouldNotUseDistributedCacheMessage { get; set; }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,11 @@ protected override async Task RemoveKeyAsync(string cacheKey, CacheSerializerHin
{
const string remove = "Remove";

if (!string.IsNullOrEmpty(cacheSerializerHints.ShouldNotUseDistributedCacheMessage))
{
throw new InvalidOperationException(TokenCacheErrorMessage.CannotUseDistributedCache + " " + cacheSerializerHints?.ShouldNotUseDistributedCacheMessage);
}

if (_memoryCache != null)
{
_memoryCache.Remove(cacheKey);
Expand Down Expand Up @@ -149,6 +154,11 @@ await L2OperationWithRetryOnFailureAsync(
byte[]? result = null;
var telemetryData = cacheSerializerHints.TelemetryData;

if (!string.IsNullOrEmpty(cacheSerializerHints.ShouldNotUseDistributedCacheMessage))
{
throw new InvalidOperationException(TokenCacheErrorMessage.CannotUseDistributedCache + " " + cacheSerializerHints?.ShouldNotUseDistributedCacheMessage);
}

if (_memoryCache != null)
{
// check memory cache first
Expand Down Expand Up @@ -240,6 +250,11 @@ protected override async Task WriteCacheBytesAsync(

DateTimeOffset? cacheExpiry = cacheSerializerHints?.SuggestedCacheExpiry;

if (!string.IsNullOrEmpty(cacheSerializerHints?.ShouldNotUseDistributedCacheMessage))
{
throw new InvalidOperationException(TokenCacheErrorMessage.CannotUseDistributedCache + " " + cacheSerializerHints?.ShouldNotUseDistributedCacheMessage);
}

if (_memoryCache != null)
{
MemoryCacheEntryOptions memoryCacheEntryOptions = new MemoryCacheEntryOptions
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
const Microsoft.Identity.Web.TokenCacheErrorMessage.CannotUseDistributedCache = "IDW10803: Cannot use distributed cache for the current configuration. Use an in memory cache instead." -> string!
Microsoft.Identity.Web.TokenCacheProviders.CacheSerializerHints.ShouldNotUseDistributedCacheMessage.get -> string?
Microsoft.Identity.Web.TokenCacheProviders.CacheSerializerHints.ShouldNotUseDistributedCacheMessage.set -> void
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,11 @@ private byte[] ProtectBytes(byte[] msalBytes)
}

private static CacheSerializerHints CreateHintsFromArgs(TokenCacheNotificationArgs args) => new CacheSerializerHints
{ CancellationToken = args.CancellationToken, SuggestedCacheExpiry = args.SuggestedCacheExpiry, TelemetryData = args.TelemetryData };
{ CancellationToken = args.CancellationToken,
SuggestedCacheExpiry = args.SuggestedCacheExpiry,
TelemetryData = args.TelemetryData,
ShouldNotUseDistributedCacheMessage = args.NoDistributedCacheUseReason
};

private async Task OnBeforeAccessAsync(TokenCacheNotificationArgs args)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,6 @@ internal static class TokenCacheErrorMessage
{
public const string InitializeAsyncIsObsolete = "IDW10801: Use Initialize instead. See https://aka.ms/ms-id-web/1.9.0. ";
public const string ExceptionDeserializingCache = "IDW10802: Exception occurred while deserializing token cache. See https://aka.ms/msal-net-token-cache-serialization general guidance and https://aka.ms/ms-id-web/token-cache-troubleshooting for token cache troubleshooting information.";
public const string CannotUseDistributedCache = "IDW10803: Cannot use distributed cache for the current configuration. Use an in memory cache instead.";
Comment thread
trwalke marked this conversation as resolved.
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,11 @@ public async Task TestRemoveKeyAsync(string cacheKey)
await RemoveKeyAsync(cacheKey);
}

public async Task TestRemoveKeyAsync(string cacheKey, CacheSerializerHints cacheSerializerHints)
{
await RemoveKeyAsync(cacheKey, cacheSerializerHints?? new CacheSerializerHints());
}

public async Task TestWriteCacheBytesAsync(string cacheKey, byte[] bytes, CacheSerializerHints? cacheSerializerHints = null)
{
await WriteCacheBytesAsync(cacheKey, bytes, cacheSerializerHints);
Expand All @@ -44,6 +49,11 @@ public async Task TestWriteCacheBytesAsync(string cacheKey, byte[] bytes, CacheS
return await ReadCacheBytesAsync(cacheKey);
}

public async Task<byte[]?> TestReadCacheBytesAsync(string cacheKey, CacheSerializerHints cacheSerializerHints)
{
return await ReadCacheBytesAsync(cacheKey, cacheSerializerHints?? new CacheSerializerHints());
}

public async Task<byte[]?> TestReadCacheBytesAsync(string cacheKey, TelemetryData telemetryData)
{
return await ReadCacheBytesAsync(cacheKey, new CacheSerializerHints() { TelemetryData = telemetryData });
Expand Down
32 changes: 32 additions & 0 deletions tests/Microsoft.Identity.Web.Test/L1L2CacheTests.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using System;
using System.Threading.Tasks;
using Microsoft.Extensions.Caching.Distributed;
using Microsoft.Extensions.Caching.Memory;
Expand Down Expand Up @@ -391,6 +392,37 @@ public async Task RemoveOneCacheItem_OneCacheItemsRemains_TestAsync()
Assert.Empty(L2Cache._dict);
}


[Fact]
public async Task SetLCache_ThrowIf_ShouldNotUseDistributedCache_TestAsync()
{
// Arrange
byte[] cache = new byte[3];
AssertCacheValues(_testCacheAdapter);
Assert.NotNull(_testCacheAdapter._memoryCache);
Assert.Equal(0, _testCacheAdapter._memoryCache.Count);
Assert.Empty(L2Cache._dict);
CacheSerializerHints cacheSerializerHints = new CacheSerializerHints();
cacheSerializerHints.SuggestedCacheExpiry = System.DateTimeOffset.Now - System.TimeSpan.FromHours(1);
cacheSerializerHints.ShouldNotUseDistributedCacheMessage = "DoNotUseDistCache";

// Act
var ex1 = await Assert.ThrowsAsync<InvalidOperationException>(async () =>
await _testCacheAdapter.TestWriteCacheBytesAsync(DefaultCacheKey, cache, cacheSerializerHints));

var ex2 = await Assert.ThrowsAsync<InvalidOperationException>(async () =>
await _testCacheAdapter.TestReadCacheBytesAsync(DefaultCacheKey, cacheSerializerHints));

var ex3 = await Assert.ThrowsAsync<InvalidOperationException>(async () =>
await _testCacheAdapter.TestRemoveKeyAsync(DefaultCacheKey, cacheSerializerHints));

// Assert
Assert.Equal(TokenCacheErrorMessage.CannotUseDistributedCache + " DoNotUseDistCache", ex1.Message);
Assert.Equal(TokenCacheErrorMessage.CannotUseDistributedCache + " DoNotUseDistCache", ex2.Message);
Assert.Equal(TokenCacheErrorMessage.CannotUseDistributedCache + " DoNotUseDistCache", ex3.Message);
Assert.Equal(0, _testCacheAdapter._memoryCache.Count);
}

private static void AssertCacheValues(TestMsalDistributedTokenCacheAdapter testCache)
{
Assert.NotNull(testCache);
Expand Down
Loading