Skip to content

Commit

Permalink
Add _lastKnownGoodConfigurationCache into ctor
Browse files Browse the repository at this point in the history
  • Loading branch information
ciaozhang committed Feb 23, 2023
1 parent f2ecd68 commit 6899abb
Show file tree
Hide file tree
Showing 8 changed files with 105 additions and 31 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -1258,13 +1258,13 @@ private async Task<TokenValidationResult> ValidateTokenAsync(JsonWebToken jsonWe
}
}

if (TokenUtilities.ShouldValidateWithLKG(validationParameters))
if (validationParameters.ConfigurationManager.UseLastKnownGoodConfiguration)
{
validationParameters.RefreshBeforeValidation = false;
validationParameters.ValidateWithLKG = true;
var recoverableException = tokenValidationResult.Exception;

foreach (BaseConfiguration lkgConfiguration in validationParameters.ConfigurationManager.GetValidLkgConfiguraitons())
foreach (BaseConfiguration lkgConfiguration in validationParameters.ConfigurationManager.GetValidLkgConfigurations())
{
if (!lkgConfiguration.Equals(currentConfiguration) && TokenUtilities.IsRecoverableConfiguration(jsonWebToken.Kid, currentConfiguration, lkgConfiguration, recoverableException))
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using System.Threading;
using System.Threading.Tasks;
using Microsoft.IdentityModel.Logging;
using Microsoft.IdentityModel.Protocols.Configuration;
using Microsoft.IdentityModel.Tokens;

namespace Microsoft.IdentityModel.Protocols
Expand All @@ -33,7 +34,7 @@ public class ConfigurationManager<T> : BaseConfigurationManager, IConfigurationM
/// Static initializer for a new object. Static initializers run before the first instance of the type is created.
/// </summary>
static ConfigurationManager()
{
{
}

/// <summary>
Expand Down Expand Up @@ -81,6 +82,12 @@ public ConfigurationManager(string metadataAddress, IConfigurationRetriever<T> c
_docRetriever = docRetriever;
_configRetriever = configRetriever;
_refreshLock = new SemaphoreSlim(1);

_lastKnownGoodConfigurationCache = new EventBasedLRUCache<BaseConfiguration, DateTime>(
LastKnownGoodConfigurationCacheOptions.DefaultLastKnownGoodConfigurationSizeLimit,
TaskCreationOptions.None,
new BaseConfigurationComparer(),
true);
}

/// <summary>
Expand All @@ -100,6 +107,28 @@ public ConfigurationManager(string metadataAddress, IConfigurationRetriever<T> c
_configValidator = configValidator;
}

/// <summary>
/// Instantiates a new <see cref="ConfigurationManager{T}"/> with cinfiguration validator that manages automatic and controls refreshing on configuration data.
/// </summary>
/// <param name="metadataAddress">The address to obtain configuration.</param>
/// <param name="configRetriever">The <see cref="IConfigurationRetriever{T}"/></param>
/// <param name="docRetriever">The <see cref="IDocumentRetriever"/> that reaches out to obtain the configuration.</param>
/// <param name="configValidator">The <see cref="IConfigurationValidator{T}"/></param>
/// <param name="lkgCacheOptions">The <see cref="LastKnownGoodConfigurationCacheOptions"/></param>
/// <exception cref="ArgumentNullException">If 'configValidator' is null.</exception>
public ConfigurationManager(string metadataAddress, IConfigurationRetriever<T> configRetriever, IDocumentRetriever docRetriever, IConfigurationValidator<T> configValidator, LastKnownGoodConfigurationCacheOptions lkgCacheOptions)
: this(metadataAddress, configRetriever, docRetriever, configValidator)
{
if (lkgCacheOptions == null)
throw LogHelper.LogArgumentNullException(nameof(lkgCacheOptions));

_lastKnownGoodConfigurationCache = new EventBasedLRUCache<BaseConfiguration, DateTime>(
lkgCacheOptions.LastKnownGoodConfigurationSizeLimit,
TaskCreationOptions.None,
lkgCacheOptions.BaseConfigurationComparer,
true);
}

/// <summary>
/// Obtains an updated version of Configuration.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using System;
using System.Collections.Generic;

using Microsoft.IdentityModel.Tokens;
using Microsoft.IdentityModel.Logging;

namespace Microsoft.IdentityModel.Protocols.Configuration
{
/// <summary>
/// Specifies the LastKnownGoodConfigurationCacheOptions which can be used to configure the internal LKG configuration cache.
/// See <see cref="EventBasedLRUCache{TKey, TValue}"/> for more details.
/// </summary>
public class LastKnownGoodConfigurationCacheOptions
{
private IEqualityComparer<BaseConfiguration> _baseConfigurationComparer = new BaseConfigurationComparer();
private int _lastKnownGoodConfigurationSizeLimit = DefaultLastKnownGoodConfigurationSizeLimit;

/// <summary>
/// 10 is the default size limit of the cache (in number of items) for last known good configuration.
/// </summary>
public static readonly int DefaultLastKnownGoodConfigurationSizeLimit = 10;

/// <summary>
/// Gets or sets the BaseConfgiurationComparer that to compare <see cref="BaseConfiguration"/>.
/// </summary>
public IEqualityComparer<BaseConfiguration> BaseConfigurationComparer
{
get { return _baseConfigurationComparer; }
set
{
_baseConfigurationComparer = value ?? throw LogHelper.LogExceptionMessage(new ArgumentNullException(nameof(value)));
}
}

/// <summary>
/// The size limit of the cache (in number of items) for last known good configuration.
/// </summary>
public int LastKnownGoodConfigurationSizeLimit
{
get { return _lastKnownGoodConfigurationSizeLimit; }
set
{
_lastKnownGoodConfigurationSizeLimit = (value > 0) ? value : throw LogHelper.LogExceptionMessage(new ArgumentOutOfRangeException(nameof(value)));
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// Licensed under the MIT License.

using Microsoft.IdentityModel.Logging;
using Microsoft.IdentityModel.Protocols.Configuration;
using Microsoft.IdentityModel.Tokens;
using System;
using System.Threading;
Expand All @@ -28,6 +29,11 @@ public StaticConfigurationManager(T configuration)
throw LogHelper.LogExceptionMessage(new ArgumentNullException(nameof(configuration), LogHelper.FormatInvariant(LogMessages.IDX20000, LogHelper.MarkAsNonPII(nameof(configuration)))));

_configuration = configuration;
_lastKnownGoodConfigurationCache = new EventBasedLRUCache<BaseConfiguration, DateTime>(
LastKnownGoodConfigurationCacheOptions.DefaultLastKnownGoodConfigurationSizeLimit,
TaskCreationOptions.None,
new BaseConfigurationComparer(),
true);
}

/// <summary>
Expand Down
18 changes: 10 additions & 8 deletions src/Microsoft.IdentityModel.Tokens/BaseConfigurationManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@ public abstract class BaseConfigurationManager
private BaseConfiguration _lastKnownGoodConfiguration;
private DateTime? _lastKnownGoodConfigFirstUse = null;

private EventBasedLRUCache<BaseConfiguration, DateTime> _lkgConfigurationCache = null;
internal EventBasedLRUCache<BaseConfiguration, DateTime> _lastKnownGoodConfigurationCache;
//private EventBasedLRUCache<BaseConfiguration, DateTime> _lastKnownGoodConfigurationCache = new EventBasedLRUCache<BaseConfiguration, DateTime>(10, TaskCreationOptions.None, new BaseConfigurationComparer(), true, maintainLRU: true);

private int _lastKnownGoodConfigurationSizeLimit = DefaultLastKnownGoodConfigurationSizeLimit;
private IEqualityComparer<BaseConfiguration> _baseConfigurationComparer = new BaseConfigurationComparer();

Expand Down Expand Up @@ -90,12 +92,12 @@ public virtual Task<BaseConfiguration> GetBaseConfigurationAsync(CancellationTok
/// Gets all valid last known good configurations.
/// </summary>
/// <returns>A collection of all valid last known good configurations.</returns>
internal ICollection<BaseConfiguration> GetValidLkgConfiguraitons()
internal ICollection<BaseConfiguration> GetValidLkgConfigurations()
{
if (_lkgConfigurationCache == null)
if (_lastKnownGoodConfigurationCache == null)
return null;

return _lkgConfigurationCache.ToArray().Where(x => x.Value.Value > DateTime.UtcNow).Select(x => x.Key).ToArray();
return _lastKnownGoodConfigurationCache.ToArray().Where(x => x.Value.Value > DateTime.UtcNow).Select(x => x.Key).ToArray();
}

/// <summary>
Expand All @@ -112,11 +114,11 @@ public BaseConfiguration LastKnownGoodConfiguration
_lastKnownGoodConfiguration = value ?? throw LogHelper.LogArgumentNullException(nameof(value));
_lastKnownGoodConfigFirstUse = DateTime.UtcNow;

if (_lkgConfigurationCache == null)
_lkgConfigurationCache = new EventBasedLRUCache<BaseConfiguration, DateTime>(LastKnownGoodConfigurationSizeLimit, TaskCreationOptions.None, BaseConfigurationComparer, true, maintainLRU: true);
if (_lastKnownGoodConfigurationCache == null)
_lastKnownGoodConfigurationCache = new EventBasedLRUCache<BaseConfiguration, DateTime>(LastKnownGoodConfigurationSizeLimit, TaskCreationOptions.None, BaseConfigurationComparer, true, maintainLRU: true);

// LRU cache will remove the expired configuration
_lkgConfigurationCache.SetValue(_lastKnownGoodConfiguration, DateTime.UtcNow + LastKnownGoodLifetime, DateTime.UtcNow + LastKnownGoodLifetime);
_lastKnownGoodConfigurationCache.SetValue(_lastKnownGoodConfiguration, DateTime.UtcNow + LastKnownGoodLifetime, DateTime.UtcNow + LastKnownGoodLifetime);
}
}

Expand Down
13 changes: 0 additions & 13 deletions src/Microsoft.IdentityModel.Tokens/TokenUtilities.cs
Original file line number Diff line number Diff line change
Expand Up @@ -233,18 +233,5 @@ internal static bool IsRecoverableConfiguration(string kid, BaseConfiguration cu

return false;
}

/// <summary>
/// Check if the token can be validated by LKG.
/// </summary>
/// <param name="validationParameters">The <see cref="TokenValidationParameters"/> to be used for validation.</param>
/// <returns><c>true</c> if the token can be validated by LKG, <c>false</c>.</returns>
internal static bool ShouldValidateWithLKG(TokenValidationParameters validationParameters)
{
ICollection<BaseConfiguration> validLkgConfiguraitons = validationParameters.ConfigurationManager.GetValidLkgConfiguraitons();
return (validationParameters.ConfigurationManager.UseLastKnownGoodConfiguration
&& validLkgConfiguraitons != null
&& validLkgConfiguraitons.Any());
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -929,15 +929,15 @@ private ClaimsPrincipal ValidateToken(string token, JwtSecurityToken outerToken,
}
}

if (TokenUtilities.ShouldValidateWithLKG(validationParameters))
if (validationParameters.ConfigurationManager.UseLastKnownGoodConfiguration)
{
validationParameters.RefreshBeforeValidation = false;
validationParameters.ValidateWithLKG = true;
var recoverableException = exceptionThrown.SourceException;
string kid = outerToken != null ? outerToken.Header.Kid :
(ValidateSignatureUsingDelegates(token, validationParameters, null) ?? GetJwtSecurityTokenFromToken(token, validationParameters)).Header.Kid;

foreach (BaseConfiguration lkgConfiguration in validationParameters.ConfigurationManager.GetValidLkgConfiguraitons())
foreach (BaseConfiguration lkgConfiguration in validationParameters.ConfigurationManager.GetValidLkgConfigurations())
{
if (!lkgConfiguration.Equals(currentConfiguration) && TokenUtilities.IsRecoverableConfiguration(kid, currentConfiguration, lkgConfiguration, recoverableException))
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -393,19 +393,19 @@ public void TestConfigurationComparer()
configWithSameKidDiffKeyMaterial.SigningKeys.Add(new SymmetricSecurityKey(KeyingMaterial.DefaultSymmetricSecurityKey_128.Key) { KeyId = KeyingMaterial.DefaultSymmetricSecurityKey_256.KeyId });

var configurationManager = new MockConfigurationManager<OpenIdConnectConfiguration>(config, config);
IdentityComparer.AreEqual(configurationManager.GetValidLkgConfiguraitons().Count, 1, context);
IdentityComparer.AreEqual(configurationManager.GetValidLkgConfigurations().Count, 1, context);

configurationManager.LastKnownGoodConfiguration = configWithSameKeysDiffOrder;
IdentityComparer.AreEqual(configurationManager.GetValidLkgConfiguraitons().Count, 1, context);
IdentityComparer.AreEqual(configurationManager.GetValidLkgConfigurations().Count, 1, context);

configurationManager.LastKnownGoodConfiguration = configWithOverlappingKey;
IdentityComparer.AreEqual(configurationManager.GetValidLkgConfiguraitons().Count, 2, context);
IdentityComparer.AreEqual(configurationManager.GetValidLkgConfigurations().Count, 2, context);

configurationManager.LastKnownGoodConfiguration = configWithOverlappingKeyDiffissuer;
IdentityComparer.AreEqual(configurationManager.GetValidLkgConfiguraitons().Count, 3, context);
IdentityComparer.AreEqual(configurationManager.GetValidLkgConfigurations().Count, 3, context);

configurationManager.LastKnownGoodConfiguration = configWithSameKidDiffKeyMaterial;
IdentityComparer.AreEqual(configurationManager.GetValidLkgConfiguraitons().Count, 4, context);
IdentityComparer.AreEqual(configurationManager.GetValidLkgConfigurations().Count, 4, context);

TestUtilities.AssertFailIfErrors(context);
}
Expand Down

0 comments on commit 6899abb

Please sign in to comment.