Rename KeyLifetimeOptions -> KeyManagementOptions
Simplify default key resolution logic Introduce API for disabling automatic key generation
This commit is contained in:
parent
20fe4f8d63
commit
58c823bc45
|
|
@ -113,6 +113,36 @@ namespace Microsoft.AspNet.DataProtection
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Configures the data protection system not to generate new keys automatically.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The 'this' instance.</returns>
|
||||||
|
/// <remarks>
|
||||||
|
/// Calling this API corresponds to setting <see cref="KeyManagementOptions.AutoGenerateKeys"/>
|
||||||
|
/// to 'false'. See that property's documentation for more information.
|
||||||
|
/// </remarks>
|
||||||
|
public DataProtectionConfiguration DisableAutomaticKeyGeneration()
|
||||||
|
{
|
||||||
|
Services.Configure<KeyManagementOptions>(options =>
|
||||||
|
{
|
||||||
|
options.AutoGenerateKeys = false;
|
||||||
|
});
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Configures the data protection system to persist keys in storage as plaintext.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The 'this' instance.</returns>
|
||||||
|
/// <remarks>
|
||||||
|
/// Caution: cryptographic key material will not be protected at rest.
|
||||||
|
/// </remarks>
|
||||||
|
public DataProtectionConfiguration DisableProtectionOfKeysAtRest()
|
||||||
|
{
|
||||||
|
RemoveAllServicesOfType(typeof(IXmlEncryptor));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Configures the data protection system to persist keys to the specified directory.
|
/// Configures the data protection system to persist keys to the specified directory.
|
||||||
/// This path may be on the local machine or may point to a UNC share.
|
/// This path may be on the local machine or may point to a UNC share.
|
||||||
|
|
@ -241,30 +271,17 @@ namespace Microsoft.AspNet.DataProtection
|
||||||
/// Sets the default lifetime of keys created by the data protection system.
|
/// Sets the default lifetime of keys created by the data protection system.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="lifetime">The lifetime (time before expiration) for newly-created keys.
|
/// <param name="lifetime">The lifetime (time before expiration) for newly-created keys.
|
||||||
/// See <see cref="KeyLifetimeOptions.NewKeyLifetime"/> for more information and
|
/// See <see cref="KeyManagementOptions.NewKeyLifetime"/> for more information and
|
||||||
/// usage notes.</param>
|
/// usage notes.</param>
|
||||||
/// <returns>The 'this' instance.</returns>
|
/// <returns>The 'this' instance.</returns>
|
||||||
public DataProtectionConfiguration SetDefaultKeyLifetime(TimeSpan lifetime)
|
public DataProtectionConfiguration SetDefaultKeyLifetime(TimeSpan lifetime)
|
||||||
{
|
{
|
||||||
Services.Configure<KeyLifetimeOptions>(options =>
|
Services.Configure<KeyManagementOptions>(options =>
|
||||||
{
|
{
|
||||||
options.NewKeyLifetime = lifetime;
|
options.NewKeyLifetime = lifetime;
|
||||||
});
|
});
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Configures the data protection system to persist keys in storage as plaintext.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>The 'this' instance.</returns>
|
|
||||||
/// <remarks>
|
|
||||||
/// Caution: cryptographic key material will not be protected at rest.
|
|
||||||
/// </remarks>
|
|
||||||
public DataProtectionConfiguration SuppressProtectionOfKeysAtRest()
|
|
||||||
{
|
|
||||||
RemoveAllServicesOfType(typeof(IXmlEncryptor));
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Configures the data protection system to use the specified cryptographic algorithms
|
/// Configures the data protection system to use the specified cryptographic algorithms
|
||||||
|
|
|
||||||
|
|
@ -72,7 +72,7 @@ namespace Microsoft.AspNet.DataProtection
|
||||||
{
|
{
|
||||||
var keyRingProvider = new KeyRingProvider(
|
var keyRingProvider = new KeyRingProvider(
|
||||||
keyManager: services.GetRequiredService<IKeyManager>(),
|
keyManager: services.GetRequiredService<IKeyManager>(),
|
||||||
keyLifetimeOptions: services.GetService<IOptions<KeyLifetimeOptions>>()?.Options, // might be null
|
keyManagementOptions: services.GetService<IOptions<KeyManagementOptions>>()?.Options, // might be null
|
||||||
services: services);
|
services: services);
|
||||||
dataProtectionProvider = new KeyRingBasedDataProtectionProvider(keyRingProvider, services);
|
dataProtectionProvider = new KeyRingBasedDataProtectionProvider(keyRingProvider, services);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -39,14 +39,14 @@ namespace Microsoft.Framework.DependencyInjection
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// An <see cref="IConfigureOptions{KeyLifetimeOptions}"/> where the key lifetime is specified explicitly.
|
/// An <see cref="IConfigureOptions{KeyManagementOptions}"/> where the key lifetime is specified explicitly.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
||||||
public static ServiceDescriptor ConfigureOptions_DefaultKeyLifetime(int numDays)
|
public static ServiceDescriptor ConfigureOptions_DefaultKeyLifetime(int numDays)
|
||||||
{
|
{
|
||||||
return ServiceDescriptor.Transient<IConfigureOptions<KeyLifetimeOptions>>(services =>
|
return ServiceDescriptor.Transient<IConfigureOptions<KeyManagementOptions>>(services =>
|
||||||
{
|
{
|
||||||
return new ConfigureOptions<KeyLifetimeOptions>(options =>
|
return new ConfigureOptions<KeyManagementOptions>(options =>
|
||||||
{
|
{
|
||||||
options.NewKeyLifetime = TimeSpan.FromDays(numDays);
|
options.NewKeyLifetime = TimeSpan.FromDays(numDays);
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -18,10 +18,10 @@ namespace Microsoft.AspNet.DataProtection.KeyManagement
|
||||||
/// and persisted to the keyring to ensure uninterrupted service.
|
/// and persisted to the keyring to ensure uninterrupted service.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// If the expiration window is 5 days and the current key expires within 5 days,
|
/// If the propagation time is 5 days and the current key expires within 5 days,
|
||||||
/// a new key will be generated.
|
/// a new key will be generated.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
private readonly TimeSpan _keyGenBeforeExpirationWindow;
|
private readonly TimeSpan _keyPropagationWindow;
|
||||||
|
|
||||||
private readonly ILogger _logger;
|
private readonly ILogger _logger;
|
||||||
|
|
||||||
|
|
@ -36,9 +36,9 @@ namespace Microsoft.AspNet.DataProtection.KeyManagement
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
private readonly TimeSpan _maxServerToServerClockSkew;
|
private readonly TimeSpan _maxServerToServerClockSkew;
|
||||||
|
|
||||||
public DefaultKeyResolver(TimeSpan keyGenBeforeExpirationWindow, TimeSpan maxServerToServerClockSkew, IServiceProvider services)
|
public DefaultKeyResolver(TimeSpan keyPropagationWindow, TimeSpan maxServerToServerClockSkew, IServiceProvider services)
|
||||||
{
|
{
|
||||||
_keyGenBeforeExpirationWindow = keyGenBeforeExpirationWindow;
|
_keyPropagationWindow = keyPropagationWindow;
|
||||||
_maxServerToServerClockSkew = maxServerToServerClockSkew;
|
_maxServerToServerClockSkew = maxServerToServerClockSkew;
|
||||||
_logger = services.GetLogger<DefaultKeyResolver>();
|
_logger = services.GetLogger<DefaultKeyResolver>();
|
||||||
}
|
}
|
||||||
|
|
@ -52,82 +52,61 @@ namespace Microsoft.AspNet.DataProtection.KeyManagement
|
||||||
|
|
||||||
private IKey FindDefaultKey(DateTimeOffset now, IEnumerable<IKey> allKeys, out bool callerShouldGenerateNewKey)
|
private IKey FindDefaultKey(DateTimeOffset now, IEnumerable<IKey> allKeys, out bool callerShouldGenerateNewKey)
|
||||||
{
|
{
|
||||||
// the key with the most recent activation date where the activation date is in the past
|
// find the preferred default key (allowing for server-to-server clock skew)
|
||||||
IKey keyMostRecentlyActivated = (from key in allKeys
|
var preferredDefaultKey = (from key in allKeys
|
||||||
where key.ActivationDate <= now
|
where key.ActivationDate <= now + _maxServerToServerClockSkew
|
||||||
orderby key.ActivationDate descending
|
orderby key.ActivationDate descending, key.KeyId ascending
|
||||||
select key).FirstOrDefault();
|
select key).FirstOrDefault();
|
||||||
|
|
||||||
if (keyMostRecentlyActivated != null)
|
if (preferredDefaultKey != null)
|
||||||
{
|
{
|
||||||
if (_logger.IsVerboseLevelEnabled())
|
if (_logger.IsVerboseLevelEnabled())
|
||||||
{
|
{
|
||||||
_logger.LogVerbose("Considering key '{0:D}' with expiration date {1:u} as default key candidate.", keyMostRecentlyActivated.KeyId, keyMostRecentlyActivated.ExpirationDate);
|
_logger.LogVerbose("Considering key '{0:D}' with expiration date {1:u} as default key.", preferredDefaultKey.KeyId, preferredDefaultKey.ExpirationDate);
|
||||||
}
|
}
|
||||||
|
|
||||||
// if the key has been revoked or is expired, it is no longer a candidate
|
// if the key has been revoked or is expired, it is no longer a candidate
|
||||||
if (keyMostRecentlyActivated.IsExpired(now) || keyMostRecentlyActivated.IsRevoked)
|
if (preferredDefaultKey.IsExpired(now) || preferredDefaultKey.IsRevoked)
|
||||||
{
|
{
|
||||||
if (_logger.IsVerboseLevelEnabled())
|
if (_logger.IsVerboseLevelEnabled())
|
||||||
{
|
{
|
||||||
_logger.LogVerbose("Key '{0:D}' no longer eligible as default key candidate because it is expired or revoked.", keyMostRecentlyActivated.KeyId);
|
_logger.LogVerbose("Key '{0:D}' is no longer under consideration as default key because it is expired or revoked.", preferredDefaultKey.KeyId);
|
||||||
}
|
}
|
||||||
keyMostRecentlyActivated = null;
|
preferredDefaultKey = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// There's an interesting edge case here. If two keys have an activation date in the past and
|
// Only the key that has been most recently activated is eligible to be the preferred default,
|
||||||
// an expiration date in the future, and if the most recently activated of those two keys is
|
// and only if it hasn't expired or been revoked. This is intentional: generating a new key is
|
||||||
// revoked, we won't consider the older key a valid candidate. This is intentional: generating
|
// an implicit signal that we should stop using older keys (even if they're not revoked), so
|
||||||
// a new key is an implicit signal that we should stop using older keys without explicitly
|
// activating a new key should permanently mark all older keys as non-preferred.
|
||||||
// revoking them.
|
|
||||||
|
|
||||||
// if the key's expiration is beyond our safety window, we can use this key
|
if (preferredDefaultKey != null)
|
||||||
if (keyMostRecentlyActivated != null && keyMostRecentlyActivated.ExpirationDate - now > _keyGenBeforeExpirationWindow)
|
|
||||||
{
|
{
|
||||||
callerShouldGenerateNewKey = false;
|
// Does *any* key in the key ring fulfill the requirement that its activation date is prior
|
||||||
return keyMostRecentlyActivated;
|
// to the preferred default key's expiration date (allowing for skew) and that it will
|
||||||
}
|
// remain valid one propagation cycle from now? If so, the caller doesn't need to add a
|
||||||
|
// new key.
|
||||||
|
callerShouldGenerateNewKey = !allKeys.Any(key =>
|
||||||
|
key.ActivationDate <= (preferredDefaultKey.ExpirationDate + _maxServerToServerClockSkew)
|
||||||
|
&& !key.IsExpired(now + _keyPropagationWindow)
|
||||||
|
&& !key.IsRevoked);
|
||||||
|
|
||||||
// the key with the nearest activation date where the activation date is in the future
|
|
||||||
// and the key isn't expired or revoked
|
|
||||||
IKey keyNextPendingActivation = (from key in allKeys
|
|
||||||
where key.ActivationDate > now && !key.IsExpired(now) && !key.IsRevoked
|
|
||||||
orderby key.ActivationDate ascending
|
|
||||||
select key).FirstOrDefault();
|
|
||||||
|
|
||||||
// if we have a valid current key, return it, and signal to the caller that he must perform
|
|
||||||
// the keygen step only if the next key pending activation won't be activated until *after*
|
|
||||||
// the current key expires (allowing for server-to-server skew)
|
|
||||||
if (keyMostRecentlyActivated != null)
|
|
||||||
{
|
|
||||||
callerShouldGenerateNewKey = (keyNextPendingActivation == null || (keyNextPendingActivation.ActivationDate - keyMostRecentlyActivated.ExpirationDate > _maxServerToServerClockSkew));
|
|
||||||
if (callerShouldGenerateNewKey && _logger.IsVerboseLevelEnabled())
|
if (callerShouldGenerateNewKey && _logger.IsVerboseLevelEnabled())
|
||||||
{
|
{
|
||||||
_logger.LogVerbose("Default key expiration imminent and repository contains no viable successor. Caller should generate a successor.");
|
_logger.LogVerbose("Default key expiration imminent and repository contains no viable successor. Caller should generate a successor.");
|
||||||
}
|
}
|
||||||
|
|
||||||
return keyMostRecentlyActivated;
|
return preferredDefaultKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
// if there's no valid current key but there is a key pending activation, we can use
|
// If we got this far, the caller must generate a key now.
|
||||||
// it only if its activation period is within the server-to-server clock skew
|
|
||||||
if (keyNextPendingActivation != null && keyNextPendingActivation.ActivationDate - now <= _maxServerToServerClockSkew)
|
|
||||||
{
|
|
||||||
if (_logger.IsVerboseLevelEnabled())
|
|
||||||
{
|
|
||||||
_logger.LogVerbose("Considering key '{0:D}' with expiration date {1:u} as default key candidate.", keyNextPendingActivation.KeyId, keyNextPendingActivation.ExpirationDate);
|
|
||||||
}
|
|
||||||
|
|
||||||
callerShouldGenerateNewKey = false;
|
|
||||||
return keyNextPendingActivation;
|
|
||||||
}
|
|
||||||
|
|
||||||
// if we got this far, there was no valid default key in the keyring
|
|
||||||
if (_logger.IsVerboseLevelEnabled())
|
if (_logger.IsVerboseLevelEnabled())
|
||||||
{
|
{
|
||||||
_logger.LogVerbose("Repository contains no viable default key. Caller should generate a key with immediate activation.");
|
_logger.LogVerbose("Repository contains no viable default key. Caller should generate a key with immediate activation.");
|
||||||
}
|
}
|
||||||
|
|
||||||
callerShouldGenerateNewKey = true;
|
callerShouldGenerateNewKey = true;
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,41 +5,58 @@ using System;
|
||||||
|
|
||||||
namespace Microsoft.AspNet.DataProtection.KeyManagement
|
namespace Microsoft.AspNet.DataProtection.KeyManagement
|
||||||
{
|
{
|
||||||
public class KeyLifetimeOptions
|
/// <summary>
|
||||||
|
/// Options that control how an <see cref="IKeyManager"/> should behave.
|
||||||
|
/// </summary>
|
||||||
|
public class KeyManagementOptions
|
||||||
{
|
{
|
||||||
private readonly TimeSpan _keyExpirationSafetyPeriod = TimeSpan.FromDays(2);
|
private static readonly TimeSpan _keyPropagationWindow = TimeSpan.FromDays(2);
|
||||||
private readonly TimeSpan _keyRingRefreshPeriod = TimeSpan.FromHours(24);
|
private static readonly TimeSpan _keyRingRefreshPeriod = TimeSpan.FromHours(24);
|
||||||
private readonly TimeSpan _maxServerClockSkew = TimeSpan.FromMinutes(5);
|
private static readonly TimeSpan _maxServerClockSkew = TimeSpan.FromMinutes(5);
|
||||||
private TimeSpan _newKeyLifetime = TimeSpan.FromDays(90);
|
private TimeSpan _newKeyLifetime = TimeSpan.FromDays(90);
|
||||||
|
|
||||||
public KeyLifetimeOptions()
|
public KeyManagementOptions()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
// copy ctor
|
// copy ctor
|
||||||
internal KeyLifetimeOptions(KeyLifetimeOptions other)
|
internal KeyManagementOptions(KeyManagementOptions other)
|
||||||
{
|
{
|
||||||
if (other != null)
|
if (other != null)
|
||||||
{
|
{
|
||||||
|
this.AutoGenerateKeys = other.AutoGenerateKeys;
|
||||||
this._newKeyLifetime = other._newKeyLifetime;
|
this._newKeyLifetime = other._newKeyLifetime;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Specifies the period before key expiration in which a new key should be generated.
|
/// Specifies whether the data protection system should auto-generate keys.
|
||||||
/// For example, if this period is 72 hours, then a new key will be created and
|
/// </summary>
|
||||||
/// persisted to storage approximately 72 hours before expiration.
|
/// <remarks>
|
||||||
|
/// If this value is 'false', the system will not generate new keys automatically.
|
||||||
|
/// The key ring must contain at least one active non-revoked key, otherwise calls
|
||||||
|
/// to <see cref="IDataProtector.Protect(byte[])"/> may fail. The system may end up
|
||||||
|
/// protecting payloads to expired keys if this property is set to 'false'.
|
||||||
|
/// The default value is 'true'.
|
||||||
|
/// </remarks>
|
||||||
|
public bool AutoGenerateKeys { get; set; } = true;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Specifies the period before key expiration in which a new key should be generated
|
||||||
|
/// so that it has time to propagate fully throughout the key ring. For example, if this
|
||||||
|
/// period is 72 hours, then a new key will be created and persisted to storage
|
||||||
|
/// approximately 72 hours before expiration.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// This value is currently fixed at 48 hours.
|
/// This value is currently fixed at 48 hours.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
internal TimeSpan KeyExpirationSafetyPeriod
|
internal TimeSpan KeyPropagationWindow
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
// This value is not settable since there's a complex interaction between
|
// This value is not settable since there's a complex interaction between
|
||||||
// it and the key ring refresh period.
|
// it and the key ring refresh period.
|
||||||
return _keyExpirationSafetyPeriod;
|
return _keyPropagationWindow;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -97,7 +114,7 @@ namespace Microsoft.AspNet.DataProtection.KeyManagement
|
||||||
{
|
{
|
||||||
if (value < TimeSpan.FromDays(7))
|
if (value < TimeSpan.FromDays(7))
|
||||||
{
|
{
|
||||||
throw new ArgumentOutOfRangeException(nameof(value), Resources.KeyLifetimeOptions_MinNewKeyLifetimeViolated);
|
throw new ArgumentOutOfRangeException(nameof(value), Resources.KeyManagementOptions_MinNewKeyLifetimeViolated);
|
||||||
}
|
}
|
||||||
_newKeyLifetime = value;
|
_newKeyLifetime = value;
|
||||||
}
|
}
|
||||||
|
|
@ -17,20 +17,20 @@ namespace Microsoft.AspNet.DataProtection.KeyManagement
|
||||||
private readonly object _cacheableKeyRingLockObj = new object();
|
private readonly object _cacheableKeyRingLockObj = new object();
|
||||||
private readonly ICacheableKeyRingProvider _cacheableKeyRingProvider;
|
private readonly ICacheableKeyRingProvider _cacheableKeyRingProvider;
|
||||||
private readonly IDefaultKeyResolver _defaultKeyResolver;
|
private readonly IDefaultKeyResolver _defaultKeyResolver;
|
||||||
private readonly KeyLifetimeOptions _keyLifetimeOptions;
|
private readonly KeyManagementOptions _keyManagementOptions;
|
||||||
private readonly IKeyManager _keyManager;
|
private readonly IKeyManager _keyManager;
|
||||||
private readonly ILogger _logger;
|
private readonly ILogger _logger;
|
||||||
|
|
||||||
public KeyRingProvider(IKeyManager keyManager, KeyLifetimeOptions keyLifetimeOptions, IServiceProvider services)
|
public KeyRingProvider(IKeyManager keyManager, KeyManagementOptions keyManagementOptions, IServiceProvider services)
|
||||||
{
|
{
|
||||||
_keyLifetimeOptions = new KeyLifetimeOptions(keyLifetimeOptions); // clone so new instance is immutable
|
_keyManagementOptions = new KeyManagementOptions(keyManagementOptions); // clone so new instance is immutable
|
||||||
_keyManager = keyManager;
|
_keyManager = keyManager;
|
||||||
_cacheableKeyRingProvider = services?.GetService<ICacheableKeyRingProvider>() ?? this;
|
_cacheableKeyRingProvider = services?.GetService<ICacheableKeyRingProvider>() ?? this;
|
||||||
_logger = services?.GetLogger<KeyRingProvider>();
|
_logger = services?.GetLogger<KeyRingProvider>();
|
||||||
_defaultKeyResolver = services?.GetService<IDefaultKeyResolver>()
|
_defaultKeyResolver = services?.GetService<IDefaultKeyResolver>()
|
||||||
?? new DefaultKeyResolver(_keyLifetimeOptions.KeyExpirationSafetyPeriod, _keyLifetimeOptions.MaxServerClockSkew, services);
|
?? new DefaultKeyResolver(_keyManagementOptions.KeyPropagationWindow, _keyManagementOptions.MaxServerClockSkew, services);
|
||||||
}
|
}
|
||||||
|
|
||||||
private CacheableKeyRing CreateCacheableKeyRingCore(DateTimeOffset now, bool allowRecursiveCalls = false)
|
private CacheableKeyRing CreateCacheableKeyRingCore(DateTimeOffset now, bool allowRecursiveCalls = false)
|
||||||
{
|
{
|
||||||
// Refresh the list of all keys
|
// Refresh the list of all keys
|
||||||
|
|
@ -67,17 +67,37 @@ namespace Microsoft.AspNet.DataProtection.KeyManagement
|
||||||
|
|
||||||
if (defaultKeyPolicy.DefaultKey == null)
|
if (defaultKeyPolicy.DefaultKey == null)
|
||||||
{
|
{
|
||||||
|
// We cannot continue if we have no default key and auto-generation of keys is disabled.
|
||||||
|
if (!_keyManagementOptions.AutoGenerateKeys)
|
||||||
|
{
|
||||||
|
if (_logger.IsErrorLevelEnabled())
|
||||||
|
{
|
||||||
|
_logger.LogError("The key ring does not contain a valid default key, and the key manager is configured with auto-generation of keys disabled.");
|
||||||
|
}
|
||||||
|
throw new InvalidOperationException(Resources.KeyRingProvider_NoDefaultKey_AutoGenerateDisabled);
|
||||||
|
}
|
||||||
|
|
||||||
// The case where there's no default key is the easiest scenario, since it
|
// The case where there's no default key is the easiest scenario, since it
|
||||||
// means that we need to create a new key with immediate activation.
|
// means that we need to create a new key with immediate activation.
|
||||||
_keyManager.CreateNewKey(activationDate: now, expirationDate: now + _keyLifetimeOptions.NewKeyLifetime);
|
_keyManager.CreateNewKey(activationDate: now, expirationDate: now + _keyManagementOptions.NewKeyLifetime);
|
||||||
return CreateCacheableKeyRingCore(now); // recursively call
|
return CreateCacheableKeyRingCore(now); // recursively call
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
// If auto-generation of keys is disabled, we cannot call CreateNewKey.
|
||||||
|
if (!_keyManagementOptions.AutoGenerateKeys)
|
||||||
|
{
|
||||||
|
if (_logger.IsWarningLevelEnabled())
|
||||||
|
{
|
||||||
|
_logger.LogWarning("Policy resolution states that a new key should be added to the key ring, but automatic generation of keys is disabled.");
|
||||||
|
}
|
||||||
|
return CreateCacheableKeyRingCoreStep2(now, cacheExpirationToken, defaultKeyPolicy.DefaultKey, allKeys);
|
||||||
|
}
|
||||||
|
|
||||||
// If there is a default key, then the new key we generate should become active upon
|
// If there is a default key, then the new key we generate should become active upon
|
||||||
// expiration of the default key. The new key lifetime is measured from the creation
|
// expiration of the default key. The new key lifetime is measured from the creation
|
||||||
// date (now), not the activation date.
|
// date (now), not the activation date.
|
||||||
_keyManager.CreateNewKey(activationDate: defaultKeyPolicy.DefaultKey.ExpirationDate, expirationDate: now + _keyLifetimeOptions.NewKeyLifetime);
|
_keyManager.CreateNewKey(activationDate: defaultKeyPolicy.DefaultKey.ExpirationDate, expirationDate: now + _keyManagementOptions.NewKeyLifetime);
|
||||||
return CreateCacheableKeyRingCore(now); // recursively call
|
return CreateCacheableKeyRingCore(now); // recursively call
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -96,7 +116,7 @@ namespace Microsoft.AspNet.DataProtection.KeyManagement
|
||||||
// servers in a cluster from trying to update the key ring simultaneously.
|
// servers in a cluster from trying to update the key ring simultaneously.
|
||||||
return new CacheableKeyRing(
|
return new CacheableKeyRing(
|
||||||
expirationToken: cacheExpirationToken,
|
expirationToken: cacheExpirationToken,
|
||||||
expirationTime: Min(defaultKey.ExpirationDate, now + GetRefreshPeriodWithJitter(_keyLifetimeOptions.KeyRingRefreshPeriod)),
|
expirationTime: Min(defaultKey.ExpirationDate, now + GetRefreshPeriodWithJitter(_keyManagementOptions.KeyRingRefreshPeriod)),
|
||||||
defaultKey: defaultKey,
|
defaultKey: defaultKey,
|
||||||
allKeys: allKeys);
|
allKeys: allKeys);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -219,19 +219,19 @@ namespace Microsoft.AspNet.DataProtection
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The default new key lifetime must be at least one week.
|
/// The new key lifetime must be at least one week.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal static string KeyLifetimeOptions_MinNewKeyLifetimeViolated
|
internal static string KeyManagementOptions_MinNewKeyLifetimeViolated
|
||||||
{
|
{
|
||||||
get { return GetString("KeyLifetimeOptions_MinNewKeyLifetimeViolated"); }
|
get { return GetString("KeyManagementOptions_MinNewKeyLifetimeViolated"); }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The default new key lifetime must be at least one week.
|
/// The new key lifetime must be at least one week.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal static string FormatKeyLifetimeOptions_MinNewKeyLifetimeViolated()
|
internal static string FormatKeyManagementOptions_MinNewKeyLifetimeViolated()
|
||||||
{
|
{
|
||||||
return GetString("KeyLifetimeOptions_MinNewKeyLifetimeViolated");
|
return GetString("KeyManagementOptions_MinNewKeyLifetimeViolated");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -378,6 +378,22 @@ namespace Microsoft.AspNet.DataProtection
|
||||||
return string.Format(CultureInfo.CurrentCulture, GetString("AlgorithmAssert_BadKeySize"), p0);
|
return string.Format(CultureInfo.CurrentCulture, GetString("AlgorithmAssert_BadKeySize"), p0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The key ring does not contain a valid default protection key. The data protection system cannot create a new key because auto-generation of keys is disabled.
|
||||||
|
/// </summary>
|
||||||
|
internal static string KeyRingProvider_NoDefaultKey_AutoGenerateDisabled
|
||||||
|
{
|
||||||
|
get { return GetString("KeyRingProvider_NoDefaultKey_AutoGenerateDisabled"); }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The key ring does not contain a valid default protection key. The data protection system cannot create a new key because auto-generation of keys is disabled.
|
||||||
|
/// </summary>
|
||||||
|
internal static string FormatKeyRingProvider_NoDefaultKey_AutoGenerateDisabled()
|
||||||
|
{
|
||||||
|
return GetString("KeyRingProvider_NoDefaultKey_AutoGenerateDisabled");
|
||||||
|
}
|
||||||
|
|
||||||
private static string GetString(string name, params string[] formatterNames)
|
private static string GetString(string name, params string[] formatterNames)
|
||||||
{
|
{
|
||||||
var value = _resourceManager.GetString(name);
|
var value = _resourceManager.GetString(name);
|
||||||
|
|
|
||||||
|
|
@ -156,8 +156,8 @@
|
||||||
<data name="TypeExtensions_BadCast" xml:space="preserve">
|
<data name="TypeExtensions_BadCast" xml:space="preserve">
|
||||||
<value>The type '{1}' is not assignable to '{0}'.</value>
|
<value>The type '{1}' is not assignable to '{0}'.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="KeyLifetimeOptions_MinNewKeyLifetimeViolated" xml:space="preserve">
|
<data name="KeyManagementOptions_MinNewKeyLifetimeViolated" xml:space="preserve">
|
||||||
<value>The default new key lifetime must be at least one week.</value>
|
<value>The new key lifetime must be at least one week.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="XmlKeyManager_DuplicateKey" xml:space="preserve">
|
<data name="XmlKeyManager_DuplicateKey" xml:space="preserve">
|
||||||
<value>The key '{0:D}' already exists in the keyring.</value>
|
<value>The key '{0:D}' already exists in the keyring.</value>
|
||||||
|
|
@ -186,4 +186,7 @@
|
||||||
<data name="AlgorithmAssert_BadKeySize" xml:space="preserve">
|
<data name="AlgorithmAssert_BadKeySize" xml:space="preserve">
|
||||||
<value>The symmetric algorithm key size of {0} bits is invalid. The key size must be between 128 and 2048 bits, inclusive, and it must be a multiple of 8 bits.</value>
|
<value>The symmetric algorithm key size of {0} bits is invalid. The key size must be between 128 and 2048 bits, inclusive, and it must be a multiple of 8 bits.</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="KeyRingProvider_NoDefaultKey_AutoGenerateDisabled" xml:space="preserve">
|
||||||
|
<value>The key ring does not contain a valid default protection key. The data protection system cannot create a new key because auto-generation of keys is disabled.</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
||||||
|
|
@ -31,9 +31,10 @@ namespace Microsoft.AspNet.DataProtection.KeyManagement
|
||||||
// Arrange
|
// Arrange
|
||||||
var resolver = CreateDefaultKeyResolver();
|
var resolver = CreateDefaultKeyResolver();
|
||||||
var key1 = CreateKey("2015-03-01 00:00:00Z", "2016-03-01 00:00:00Z");
|
var key1 = CreateKey("2015-03-01 00:00:00Z", "2016-03-01 00:00:00Z");
|
||||||
|
var key2 = CreateKey("2016-03-01 00:00:00Z", "2017-03-01 00:00:00Z");
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var resolution = resolver.ResolveDefaultKeyPolicy("2015-04-01 00:00:00Z", key1);
|
var resolution = resolver.ResolveDefaultKeyPolicy("2016-02-20 23:59:00Z", key1, key2);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Same(key1, resolution.DefaultKey);
|
Assert.Same(key1, resolution.DefaultKey);
|
||||||
|
|
@ -41,15 +42,45 @@ namespace Microsoft.AspNet.DataProtection.KeyManagement
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void ResolveDefaultKeyPolicy_ValidExistingKey_ApproachingSafetyWindow_ReturnsExistingKey_SignalsGenerateNewKey()
|
public void ResolveDefaultKeyPolicy_ValidExistingKey_AllowsForClockSkew_KeysStraddleSkewLine_ReturnsExistingKey()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var resolver = CreateDefaultKeyResolver();
|
var resolver = CreateDefaultKeyResolver();
|
||||||
var key1 = CreateKey("2015-03-01 00:00:00Z", "2015-04-01 00:00:00Z");
|
var key1 = CreateKey("2015-03-01 00:00:00Z", "2016-03-01 00:00:00Z");
|
||||||
var key2 = CreateKey("2015-04-01 00:00:00Z", "2015-05-01 00:00:00Z", isRevoked: true);
|
var key2 = CreateKey("2016-03-01 00:00:00Z", "2017-03-01 00:00:00Z");
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var resolution = resolver.ResolveDefaultKeyPolicy("2015-03-30 00:00:00Z", key1, key2);
|
var resolution = resolver.ResolveDefaultKeyPolicy("2016-02-29 23:59:00Z", key1, key2);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Same(key2, resolution.DefaultKey);
|
||||||
|
Assert.False(resolution.ShouldGenerateNewKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ResolveDefaultKeyPolicy_ValidExistingKey_AllowsForClockSkew_AllKeysInFuture_ReturnsExistingKey()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var resolver = CreateDefaultKeyResolver();
|
||||||
|
var key1 = CreateKey("2016-03-01 00:00:00Z", "2017-03-01 00:00:00Z");
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var resolution = resolver.ResolveDefaultKeyPolicy("2016-02-29 23:59:00Z", key1);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Same(key1, resolution.DefaultKey);
|
||||||
|
Assert.False(resolution.ShouldGenerateNewKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ResolveDefaultKeyPolicy_ValidExistingKey_NoSuccessor_ReturnsExistingKey_SignalsGenerateNewKey()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var resolver = CreateDefaultKeyResolver();
|
||||||
|
var key1 = CreateKey("2015-03-01 00:00:00Z", "2016-03-01 00:00:00Z");
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var resolution = resolver.ResolveDefaultKeyPolicy("2016-02-29 23:59:00Z", key1);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Same(key1, resolution.DefaultKey);
|
Assert.Same(key1, resolution.DefaultKey);
|
||||||
|
|
@ -57,20 +88,20 @@ namespace Microsoft.AspNet.DataProtection.KeyManagement
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void ResolveDefaultKeyPolicy_ValidExistingKey_ApproachingSafetyWindow_FutureKeyIsValidAndWithinSkew_ReturnsExistingKey_NoSignalToGenerateNewKey()
|
public void ResolveDefaultKeyPolicy_ValidExistingKey_NoLegitimateSuccessor_ReturnsExistingKey_SignalsGenerateNewKey()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var resolver = CreateDefaultKeyResolver();
|
var resolver = CreateDefaultKeyResolver();
|
||||||
var key1 = CreateKey("2015-03-01 00:00:00Z", "2015-04-01 00:00:00Z");
|
var key1 = CreateKey("2015-03-01 00:00:00Z", "2016-03-01 00:00:00Z");
|
||||||
var key2 = CreateKey("2015-04-01 00:00:00Z", "2015-05-01 00:00:00Z", isRevoked: true);
|
var key2 = CreateKey("2016-03-01 00:00:00Z", "2017-03-01 00:00:00Z", isRevoked: true);
|
||||||
var key3 = CreateKey("2015-04-01 00:01:00Z", "2015-05-01 00:00:00Z");
|
var key3 = CreateKey("2016-03-01 00:00:00Z", "2016-03-02 00:00:00Z"); // key expires too soon
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var resolution = resolver.ResolveDefaultKeyPolicy("2015-03-31 23:59:00Z", key1, key2, key3);
|
var resolution = resolver.ResolveDefaultKeyPolicy("2016-02-29 23:50:00Z", key1, key2, key3);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Same(key1, resolution.DefaultKey);
|
Assert.Same(key1, resolution.DefaultKey);
|
||||||
Assert.False(resolution.ShouldGenerateNewKey);
|
Assert.True(resolution.ShouldGenerateNewKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -139,7 +170,7 @@ namespace Microsoft.AspNet.DataProtection.KeyManagement
|
||||||
private static IDefaultKeyResolver CreateDefaultKeyResolver()
|
private static IDefaultKeyResolver CreateDefaultKeyResolver()
|
||||||
{
|
{
|
||||||
return new DefaultKeyResolver(
|
return new DefaultKeyResolver(
|
||||||
keyGenBeforeExpirationWindow: TimeSpan.FromDays(2),
|
keyPropagationWindow: TimeSpan.FromDays(2),
|
||||||
maxServerToServerClockSkew: TimeSpan.FromMinutes(7),
|
maxServerToServerClockSkew: TimeSpan.FromMinutes(7),
|
||||||
services: null);
|
services: null);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -140,6 +140,40 @@ namespace Microsoft.AspNet.DataProtection.KeyManagement
|
||||||
Assert.Equal(new[] { "GetCacheExpirationToken", "GetAllKeys", "ResolveDefaultKeyPolicy", "CreateNewKey", "GetCacheExpirationToken", "GetAllKeys", "ResolveDefaultKeyPolicy" }, callSequence);
|
Assert.Equal(new[] { "GetCacheExpirationToken", "GetAllKeys", "ResolveDefaultKeyPolicy", "CreateNewKey", "GetCacheExpirationToken", "GetAllKeys", "ResolveDefaultKeyPolicy" }, callSequence);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void CreateCacheableKeyRing_GenerationRequired_NoDefaultKey_KeyGenerationDisabled_Fails()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var callSequence = new List<string>();
|
||||||
|
|
||||||
|
var now = StringToDateTime("2015-03-01 00:00:00Z");
|
||||||
|
var allKeys = new IKey[0];
|
||||||
|
|
||||||
|
var keyRingProvider = SetupCreateCacheableKeyRingTestAndCreateKeyManager(
|
||||||
|
callSequence: callSequence,
|
||||||
|
getCacheExpirationTokenReturnValues: new[] { CancellationToken.None },
|
||||||
|
getAllKeysReturnValues: new[] { allKeys },
|
||||||
|
createNewKeyCallbacks: new[] {
|
||||||
|
Tuple.Create((DateTimeOffset)now, (DateTimeOffset)now + TimeSpan.FromDays(90))
|
||||||
|
},
|
||||||
|
resolveDefaultKeyPolicyReturnValues: new[]
|
||||||
|
{
|
||||||
|
Tuple.Create((DateTimeOffset)now, (IEnumerable<IKey>)allKeys, new DefaultKeyResolution()
|
||||||
|
{
|
||||||
|
DefaultKey = null,
|
||||||
|
ShouldGenerateNewKey = true
|
||||||
|
})
|
||||||
|
},
|
||||||
|
keyManagementOptions: new KeyManagementOptions() { AutoGenerateKeys = false });
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var exception = Assert.Throws<InvalidOperationException>(() => keyRingProvider.GetCacheableKeyRing(now));
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(Resources.KeyRingProvider_NoDefaultKey_AutoGenerateDisabled, exception.Message);
|
||||||
|
Assert.Equal(new[] { "GetCacheExpirationToken", "GetAllKeys", "ResolveDefaultKeyPolicy" }, callSequence);
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void CreateCacheableKeyRing_GenerationRequired_WithDefaultKey_CreatesNewKeyWithDeferredActivationAndExpirationBasedOnCreationTime()
|
public void CreateCacheableKeyRing_GenerationRequired_WithDefaultKey_CreatesNewKeyWithDeferredActivationAndExpirationBasedOnCreationTime()
|
||||||
{
|
{
|
||||||
|
|
@ -190,12 +224,51 @@ namespace Microsoft.AspNet.DataProtection.KeyManagement
|
||||||
Assert.Equal(new[] { "GetCacheExpirationToken", "GetAllKeys", "ResolveDefaultKeyPolicy", "CreateNewKey", "GetCacheExpirationToken", "GetAllKeys", "ResolveDefaultKeyPolicy" }, callSequence);
|
Assert.Equal(new[] { "GetCacheExpirationToken", "GetAllKeys", "ResolveDefaultKeyPolicy", "CreateNewKey", "GetCacheExpirationToken", "GetAllKeys", "ResolveDefaultKeyPolicy" }, callSequence);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void CreateCacheableKeyRing_GenerationRequired_WithDefaultKey_KeyGenerationDisabled_DoesNotCreateDefaultKey()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var callSequence = new List<string>();
|
||||||
|
var expirationCts = new CancellationTokenSource();
|
||||||
|
|
||||||
|
var now = StringToDateTime("2016-02-01 00:00:00Z");
|
||||||
|
var key1 = CreateKey("2015-03-01 00:00:00Z", "2016-03-01 00:00:00Z");
|
||||||
|
var allKeys = new[] { key1 };
|
||||||
|
|
||||||
|
var keyRingProvider = SetupCreateCacheableKeyRingTestAndCreateKeyManager(
|
||||||
|
callSequence: callSequence,
|
||||||
|
getCacheExpirationTokenReturnValues: new[] { expirationCts.Token },
|
||||||
|
getAllKeysReturnValues: new[] { allKeys },
|
||||||
|
createNewKeyCallbacks: null, // empty
|
||||||
|
resolveDefaultKeyPolicyReturnValues: new[]
|
||||||
|
{
|
||||||
|
Tuple.Create((DateTimeOffset)now, (IEnumerable<IKey>)allKeys, new DefaultKeyResolution()
|
||||||
|
{
|
||||||
|
DefaultKey = key1,
|
||||||
|
ShouldGenerateNewKey = true
|
||||||
|
})
|
||||||
|
},
|
||||||
|
keyManagementOptions: new KeyManagementOptions() { AutoGenerateKeys = false });
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var cacheableKeyRing = keyRingProvider.GetCacheableKeyRing(now);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(key1.KeyId, cacheableKeyRing.KeyRing.DefaultKeyId);
|
||||||
|
AssertWithinJitterRange(cacheableKeyRing.ExpirationTimeUtc, now);
|
||||||
|
Assert.True(CacheableKeyRing.IsValid(cacheableKeyRing, now));
|
||||||
|
expirationCts.Cancel();
|
||||||
|
Assert.False(CacheableKeyRing.IsValid(cacheableKeyRing, now));
|
||||||
|
Assert.Equal(new[] { "GetCacheExpirationToken", "GetAllKeys", "ResolveDefaultKeyPolicy" }, callSequence);
|
||||||
|
}
|
||||||
|
|
||||||
private static ICacheableKeyRingProvider SetupCreateCacheableKeyRingTestAndCreateKeyManager(
|
private static ICacheableKeyRingProvider SetupCreateCacheableKeyRingTestAndCreateKeyManager(
|
||||||
IList<string> callSequence,
|
IList<string> callSequence,
|
||||||
IEnumerable<CancellationToken> getCacheExpirationTokenReturnValues,
|
IEnumerable<CancellationToken> getCacheExpirationTokenReturnValues,
|
||||||
IEnumerable<IReadOnlyCollection<IKey>> getAllKeysReturnValues,
|
IEnumerable<IReadOnlyCollection<IKey>> getAllKeysReturnValues,
|
||||||
IEnumerable<Tuple<DateTimeOffset,DateTimeOffset>> createNewKeyCallbacks,
|
IEnumerable<Tuple<DateTimeOffset,DateTimeOffset>> createNewKeyCallbacks,
|
||||||
IEnumerable<Tuple<DateTimeOffset, IEnumerable<IKey>, DefaultKeyResolution>> resolveDefaultKeyPolicyReturnValues)
|
IEnumerable<Tuple<DateTimeOffset, IEnumerable<IKey>, DefaultKeyResolution>> resolveDefaultKeyPolicyReturnValues,
|
||||||
|
KeyManagementOptions keyManagementOptions = null)
|
||||||
{
|
{
|
||||||
var getCacheExpirationTokenReturnValuesEnumerator = getCacheExpirationTokenReturnValues.GetEnumerator();
|
var getCacheExpirationTokenReturnValuesEnumerator = getCacheExpirationTokenReturnValues.GetEnumerator();
|
||||||
var mockKeyManager = new Mock<IKeyManager>(MockBehavior.Strict);
|
var mockKeyManager = new Mock<IKeyManager>(MockBehavior.Strict);
|
||||||
|
|
@ -242,7 +315,7 @@ namespace Microsoft.AspNet.DataProtection.KeyManagement
|
||||||
return resolveDefaultKeyPolicyReturnValuesEnumerator.Current.Item3;
|
return resolveDefaultKeyPolicyReturnValuesEnumerator.Current.Item3;
|
||||||
});
|
});
|
||||||
|
|
||||||
return CreateKeyRingProvider(mockKeyManager.Object, mockDefaultKeyResolver.Object);
|
return CreateKeyRingProvider(mockKeyManager.Object, mockDefaultKeyResolver.Object, keyManagementOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -359,17 +432,17 @@ namespace Microsoft.AspNet.DataProtection.KeyManagement
|
||||||
serviceCollection.AddInstance<ICacheableKeyRingProvider>(cacheableKeyRingProvider);
|
serviceCollection.AddInstance<ICacheableKeyRingProvider>(cacheableKeyRingProvider);
|
||||||
return new KeyRingProvider(
|
return new KeyRingProvider(
|
||||||
keyManager: null,
|
keyManager: null,
|
||||||
keyLifetimeOptions: null,
|
keyManagementOptions: null,
|
||||||
services: serviceCollection.BuildServiceProvider());
|
services: serviceCollection.BuildServiceProvider());
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ICacheableKeyRingProvider CreateKeyRingProvider(IKeyManager keyManager, IDefaultKeyResolver defaultKeyResolver)
|
private static ICacheableKeyRingProvider CreateKeyRingProvider(IKeyManager keyManager, IDefaultKeyResolver defaultKeyResolver, KeyManagementOptions keyManagementOptions= null)
|
||||||
{
|
{
|
||||||
var serviceCollection = new ServiceCollection();
|
var serviceCollection = new ServiceCollection();
|
||||||
serviceCollection.AddInstance<IDefaultKeyResolver>(defaultKeyResolver);
|
serviceCollection.AddInstance<IDefaultKeyResolver>(defaultKeyResolver);
|
||||||
return new KeyRingProvider(
|
return new KeyRingProvider(
|
||||||
keyManager: keyManager,
|
keyManager: keyManager,
|
||||||
keyLifetimeOptions: null,
|
keyManagementOptions: keyManagementOptions,
|
||||||
services: serviceCollection.BuildServiceProvider());
|
services: serviceCollection.BuildServiceProvider());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -61,8 +61,8 @@ namespace Microsoft.AspNet.DataProtection
|
||||||
});
|
});
|
||||||
|
|
||||||
var services = serviceCollection.BuildServiceProvider();
|
var services = serviceCollection.BuildServiceProvider();
|
||||||
var keyLifetimeOptions = services.GetService<IOptions<KeyLifetimeOptions>>();
|
var keyManagementOptions = services.GetService<IOptions<KeyManagementOptions>>();
|
||||||
Assert.Equal(TimeSpan.FromDays(1024), keyLifetimeOptions.Options.NewKeyLifetime);
|
Assert.Equal(TimeSpan.FromDays(1024), keyManagementOptions.Options.NewKeyLifetime);
|
||||||
}
|
}
|
||||||
|
|
||||||
[ConditionalFact]
|
[ConditionalFact]
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue