Skip to content

Update PersistenceManager not to fail when used in a read-only file system #3913

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: development
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions generator/.DevConfigs/2cd7f333-8fa0-4666-9ad9-375ff5a7e780.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"core": {
"updateMinimum": true,
"type": "Patch",
"changeLogMessages": [
"Update `PersistenceManager` not to throw an exception when the SDK is used with a read-only file system (https://github.com/aws/aws-sdk-net/issues/3801)",
"Add `AWSConfigs.DisableLegacyPersistenceStore` option to instruct the SDK not to use the [SDK Store](https://docs.aws.amazon.com/sdk-for-net/v4/developer-guide/sdk-store.html) in its default profile resolution search"
]
}
}
35 changes: 33 additions & 2 deletions sdk/src/Core/AWSConfigs.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
using Amazon.Runtime;
using Amazon.Runtime.Telemetry;
using Amazon.Runtime.Credentials;
using Amazon.Runtime.CredentialManagement;

namespace Amazon
{
Expand Down Expand Up @@ -81,6 +82,7 @@ public static partial class AWSConfigs
internal static string _awsAccountsLocation = GetConfig(AWSProfilesLocationKey);
internal static bool _useSdkCache = GetConfigBool(UseSdkCacheKey, defaultValue: true);
internal static bool _initializeCollections = GetConfigBool(InitializeCollectionsKey, defaultValue: false);
internal static bool _disableLegacyPersistenceStore = GetConfigBool(DisableLegacyPersistenceStoreKey, defaultValue: false);
private static TelemetryProvider _telemetryProvider = new DefaultTelemetryProvider();

#if NET8_0_OR_GREATER
Expand Down Expand Up @@ -214,6 +216,7 @@ public static string AWSProfilesLocation
}

#endregion

#region StreamingUtf8JsonReaderBufferSize

/// <summary>
Expand Down Expand Up @@ -296,7 +299,7 @@ public static bool InitializeCollections
#if NET8_0_OR_GREATER
/// <summary>
/// Key for the DisableDangerousDisablePathAndQueryCanonicalization property.
/// <seealso cref="Amazon.AWSConfigs.InitializeCollections"/>
/// <seealso cref="Amazon.AWSConfigs.DisableDangerousDisablePathAndQueryCanonicalization"/>
/// </summary>
public const string DisableDangerousDisablePathAndQueryCanonicalizationKey = "AWSDisableDangerousDisablePathAndQueryCanonicalization";

Expand Down Expand Up @@ -340,7 +343,35 @@ public static List<DefaultAWSCredentialsIdentityResolver.CredentialsGenerator> A
get { return _rootConfig.AWSCredentialsGenerators; }
set { _rootConfig.AWSCredentialsGenerators = value; }
}


#endregion

#region DisableLegacyPersistenceStore

/// <summary>
/// Key for the <seealso cref="Amazon.AWSConfigs.DisableLegacyPersistenceStore"/> property.
/// </summary>
public const string DisableLegacyPersistenceStoreKey = "AWSDisableLegacyPersistenceStore";

/// <summary>
/// When attempting to retrieve configuration options for a given profile, the AWS SDK for .NET will look at both
/// the shared config file and the SDK Store by default - via the <see cref="CredentialProfileStoreChain"/>.
/// <para />
/// The SDK Store has a few limitations, such as only being available on Windows and being specific to a particular user on a particular host.
/// <para />
/// Setting this property to <c>true</c> will instruct the SDK not to check the legacy persistence store when interacting with
/// profiles (this setting is only applicable to the <see cref="CredentialProfileStoreChain"/> and it's not considered when
/// interacting with the <see cref="NetSDKCredentialsFile"/> class directly).
/// </summary>
/// <remarks>
/// The default value is <c>false</c>.
/// </remarks>
public static bool DisableLegacyPersistenceStore
{
get { return _rootConfig.DisableLegacyPersistenceStore; }
set { _rootConfig.DisableLegacyPersistenceStore = value; }
}

#endregion

#region AWS Config Sections
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,12 +99,15 @@ public bool TryGetAWSCredentials(string profileName, out AWSCredentials credenti
/// <returns>True if the profile was found, false otherwise.</returns>
public bool TryGetProfile(string profileName, out CredentialProfile profile)
{
if (string.IsNullOrEmpty(ProfilesLocation) && UserCrypto.IsUserCryptAvailable)
if (!AWSConfigs.DisableLegacyPersistenceStore)
{
var netCredentialsFile = new NetSDKCredentialsFile();
if (netCredentialsFile.TryGetProfile(profileName, out profile))
if (string.IsNullOrEmpty(ProfilesLocation) && UserCrypto.IsUserCryptAvailable)
{
return true;
var netCredentialsFile = new NetSDKCredentialsFile();
if (netCredentialsFile.TryGetProfile(profileName, out profile))
{
return true;
}
}
}

Expand Down Expand Up @@ -140,11 +143,15 @@ public List<CredentialProfile> ListProfiles()
{
var profiles = new List<CredentialProfile>();

if (string.IsNullOrEmpty(ProfilesLocation) && UserCrypto.IsUserCryptAvailable)
if (!AWSConfigs.DisableLegacyPersistenceStore)
{
var netSdkFile = new NetSDKCredentialsFile();
profiles.AddRange(netSdkFile.ListProfiles());
if (string.IsNullOrEmpty(ProfilesLocation) && UserCrypto.IsUserCryptAvailable)
{
var netSdkFile = new NetSDKCredentialsFile();
profiles.AddRange(netSdkFile.ListProfiles());
}
}

var sharedFile = new SharedCredentialsFile(ProfilesLocation);
profiles.AddRange(sharedFile.ListProfiles());

Expand All @@ -171,7 +178,7 @@ public List<CredentialProfile> ListProfiles()
/// <param name="profile">The profile to register.</param>
public void RegisterProfile(CredentialProfile profile)
{
if (string.IsNullOrEmpty(ProfilesLocation) && UserCrypto.IsUserCryptAvailable)
if (!AWSConfigs.DisableLegacyPersistenceStore && string.IsNullOrEmpty(ProfilesLocation) && UserCrypto.IsUserCryptAvailable)
{
new NetSDKCredentialsFile().RegisterProfile(profile);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,27 +88,26 @@ static PersistenceManager()

try
{
#if BCL
#if NETFRAMEWORK
SettingsStoreFolder = System.Environment.GetFolderPath(System.Environment.SpecialFolder.LocalApplicationData) + "/AWSToolkit";
#else
SettingsStoreFolder = System.Environment.GetEnvironmentVariable("HOME");
if (string.IsNullOrEmpty(SettingsStoreFolder))
SettingsStoreFolder = System.Environment.GetEnvironmentVariable("USERPROFILE");

SettingsStoreFolder = Path.Combine(SettingsStoreFolder, "AppData/Local/AWSToolkit");
SettingsStoreFolder = Path.Combine(SettingsStoreFolder, "AppData", "Local", "AWSToolkit");
#endif
if (!Directory.Exists(SettingsStoreFolder))
Directory.CreateDirectory(SettingsStoreFolder);

Instance = new PersistenceManager();
}
catch (UnauthorizedAccessException ex)
catch (Exception ex) when (ex is UnauthorizedAccessException || ex is IOException)
{
_logger.Error(ex, $"Unable to initialize '{nameof(PersistenceManager)}'. Falling back to '{nameof(InMemoryPersistenceManager)}'.");

Instance = new InMemoryPersistenceManager();
}
}
}

#endregion

Expand Down
4 changes: 3 additions & 1 deletion sdk/src/Core/Amazon.Util/Internal/RootConfig.cs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ public RegionEndpoint RegionEndpoint

public List<DefaultAWSCredentialsIdentityResolver.CredentialsGenerator> AWSCredentialsGenerators { get; set; }

public bool DisableLegacyPersistenceStore { get; set; }

private const string _rootAwsSectionName = "aws";
public RootConfig()
{
Expand All @@ -65,6 +67,7 @@ public RootConfig()
UseSdkCache = AWSConfigs._useSdkCache;
InitializeCollections = AWSConfigs._initializeCollections;
CorrectForClockSkew = true;
DisableLegacyPersistenceStore = AWSConfigs._disableLegacyPersistenceStore;

#if NET8_0_OR_GREATER
DisableDangerousDisablePathAndQueryCanonicalization = AWSConfigs._disableDangerousDisablePathAndQueryCanonicalization;
Expand Down Expand Up @@ -105,5 +108,4 @@ public XElement GetServiceSection(string service)
return null;
}
}

}