/* * 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); } } }