/*
* Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance with
* the License. A copy of the License is located at
*
* http://aws.amazon.com/apache2.0
*
* or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
* CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions
* and limitations under the License.
*/
namespace Amazon.SecretsManager.Extensions.Caching
{
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Amazon.SecretsManager.Model;
using Microsoft.Extensions.Caching.Memory;
///
/// A default class representing a cached secret from AWS Secrets Manager.
///
public class SecretCacheItem : SecretCacheObject
{
/// The cached secret value versions for this cached secret.
private readonly MemoryCache versions = new MemoryCache(new MemoryCacheOptions());
private const ushort MAX_VERSIONS_CACHE_SIZE = 10;
public SecretCacheItem(String secretId, IAmazonSecretsManager client, SecretCacheConfiguration config)
: base(secretId, client, config)
{
}
///
/// Asynchronously retrieves the most current DescribeSecretResponse from Secrets Manager
/// as part of the Refresh operation.
///
protected override async Task ExecuteRefreshAsync(CancellationToken cancellationToken = default)
{
return await client.DescribeSecretAsync(new DescribeSecretRequest { SecretId = secretId }, cancellationToken);
}
///
/// Asynchronously retrieves the GetSecretValueResponse from the proper SecretCacheVersion.
///
protected override async Task GetSecretValueAsync(DescribeSecretResponse result, CancellationToken cancellationToken = default)
{
SecretCacheVersion version = GetVersion(result);
if (version == null)
{
return null;
}
return await version.GetSecretValue(cancellationToken);
}
public override int GetHashCode()
{
return (secretId ?? string.Empty).GetHashCode();
}
public override string ToString()
{
return $"SecretCacheItem: {secretId}";
}
public override bool Equals(object obj)
{
return obj is SecretCacheItem sci && string.Equals(this.secretId, sci.secretId);
}
///
/// Retrieves the SecretCacheVersion corresponding to the Version Stage
/// specified by the SecretCacheConfiguration.
///
private SecretCacheVersion GetVersion(DescribeSecretResponse describeResult)
{
if (null == describeResult?.VersionIdsToStages) return null;
String currentVersionId = null;
foreach (KeyValuePair> entry in describeResult.VersionIdsToStages)
{
if (entry.Value.Contains(config.VersionStage))
{
currentVersionId = entry.Key;
break;
}
}
if (currentVersionId != null)
{
SecretCacheVersion version = versions.Get(currentVersionId);
if (null == version)
{
version = versions.Set(currentVersionId, new SecretCacheVersion(secretId, currentVersionId, client, config));
if (versions.Count > MAX_VERSIONS_CACHE_SIZE)
{
TrimCacheToSizeLimit();
}
}
return version;
}
return null;
}
private void TrimCacheToSizeLimit()
{
versions.Compact((double)(versions.Count - config.MaxCacheSize) / versions.Count);
}
}
}