Skip to content

Commit a083e77

Browse files
committed
fix: Update PersistenceManager not to fail when used in a read-only file system
1 parent c755bf8 commit a083e77

File tree

5 files changed

+65
-16
lines changed

5 files changed

+65
-16
lines changed
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"core": {
3+
"updateMinimum": true,
4+
"type": "Patch",
5+
"changeLogMessages": [
6+
"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)",
7+
"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"
8+
]
9+
}
10+
}

sdk/src/Core/AWSConfigs.cs

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
using Amazon.Runtime;
3030
using Amazon.Runtime.Telemetry;
3131
using Amazon.Runtime.Credentials;
32+
using Amazon.Runtime.CredentialManagement;
3233

3334
namespace Amazon
3435
{
@@ -81,6 +82,7 @@ public static partial class AWSConfigs
8182
internal static string _awsAccountsLocation = GetConfig(AWSProfilesLocationKey);
8283
internal static bool _useSdkCache = GetConfigBool(UseSdkCacheKey, defaultValue: true);
8384
internal static bool _initializeCollections = GetConfigBool(InitializeCollectionsKey, defaultValue: false);
85+
internal static bool _disableLegacyPersistenceStore = GetConfigBool(DisableLegacyPersistenceStoreKey, defaultValue: false);
8486
private static TelemetryProvider _telemetryProvider = new DefaultTelemetryProvider();
8587

8688
#if NET8_0_OR_GREATER
@@ -214,6 +216,7 @@ public static string AWSProfilesLocation
214216
}
215217

216218
#endregion
219+
217220
#region StreamingUtf8JsonReaderBufferSize
218221

219222
/// <summary>
@@ -296,7 +299,7 @@ public static bool InitializeCollections
296299
#if NET8_0_OR_GREATER
297300
/// <summary>
298301
/// Key for the DisableDangerousDisablePathAndQueryCanonicalization property.
299-
/// <seealso cref="Amazon.AWSConfigs.InitializeCollections"/>
302+
/// <seealso cref="Amazon.AWSConfigs.DisableDangerousDisablePathAndQueryCanonicalization"/>
300303
/// </summary>
301304
public const string DisableDangerousDisablePathAndQueryCanonicalizationKey = "AWSDisableDangerousDisablePathAndQueryCanonicalization";
302305

@@ -340,7 +343,35 @@ public static List<DefaultAWSCredentialsIdentityResolver.CredentialsGenerator> A
340343
get { return _rootConfig.AWSCredentialsGenerators; }
341344
set { _rootConfig.AWSCredentialsGenerators = value; }
342345
}
343-
346+
347+
#endregion
348+
349+
#region DisableLegacyPersistenceStore
350+
351+
/// <summary>
352+
/// Key for the <seealso cref="Amazon.AWSConfigs.DisableLegacyPersistenceStore"/> property.
353+
/// </summary>
354+
public const string DisableLegacyPersistenceStoreKey = "AWSDisableLegacyPersistenceStore";
355+
356+
/// <summary>
357+
/// When attempting to retrieve configuration options for a given profile, the AWS SDK for .NET will look at both
358+
/// the shared config file and the SDK Store by default - via the <see cref="CredentialProfileStoreChain"/>.
359+
/// <para />
360+
/// 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.
361+
/// <para />
362+
/// Setting this property to <c>true</c> will instruct the SDK not to check the legacy persistence store when interacting with
363+
/// profiles (this setting is only applicable to the <see cref="CredentialProfileStoreChain"/> and it's not considered when
364+
/// interacting with the <see cref="NetSDKCredentialsFile"/> class directly).
365+
/// </summary>
366+
/// <remarks>
367+
/// The default value is <c>false</c>.
368+
/// </remarks>
369+
public static bool DisableLegacyPersistenceStore
370+
{
371+
get { return _rootConfig.DisableLegacyPersistenceStore; }
372+
set { _rootConfig.DisableLegacyPersistenceStore = value; }
373+
}
374+
344375
#endregion
345376

346377
#region AWS Config Sections

sdk/src/Core/Amazon.Runtime/CredentialManagement/CredentialProfileStoreChain.cs

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -99,12 +99,15 @@ public bool TryGetAWSCredentials(string profileName, out AWSCredentials credenti
9999
/// <returns>True if the profile was found, false otherwise.</returns>
100100
public bool TryGetProfile(string profileName, out CredentialProfile profile)
101101
{
102-
if (string.IsNullOrEmpty(ProfilesLocation) && UserCrypto.IsUserCryptAvailable)
102+
if (!AWSConfigs.DisableLegacyPersistenceStore)
103103
{
104-
var netCredentialsFile = new NetSDKCredentialsFile();
105-
if (netCredentialsFile.TryGetProfile(profileName, out profile))
104+
if (string.IsNullOrEmpty(ProfilesLocation) && UserCrypto.IsUserCryptAvailable)
106105
{
107-
return true;
106+
var netCredentialsFile = new NetSDKCredentialsFile();
107+
if (netCredentialsFile.TryGetProfile(profileName, out profile))
108+
{
109+
return true;
110+
}
108111
}
109112
}
110113

@@ -140,11 +143,15 @@ public List<CredentialProfile> ListProfiles()
140143
{
141144
var profiles = new List<CredentialProfile>();
142145

143-
if (string.IsNullOrEmpty(ProfilesLocation) && UserCrypto.IsUserCryptAvailable)
146+
if (!AWSConfigs.DisableLegacyPersistenceStore)
144147
{
145-
var netSdkFile = new NetSDKCredentialsFile();
146-
profiles.AddRange(netSdkFile.ListProfiles());
148+
if (string.IsNullOrEmpty(ProfilesLocation) && UserCrypto.IsUserCryptAvailable)
149+
{
150+
var netSdkFile = new NetSDKCredentialsFile();
151+
profiles.AddRange(netSdkFile.ListProfiles());
152+
}
147153
}
154+
148155
var sharedFile = new SharedCredentialsFile(ProfilesLocation);
149156
profiles.AddRange(sharedFile.ListProfiles());
150157

@@ -171,7 +178,7 @@ public List<CredentialProfile> ListProfiles()
171178
/// <param name="profile">The profile to register.</param>
172179
public void RegisterProfile(CredentialProfile profile)
173180
{
174-
if (string.IsNullOrEmpty(ProfilesLocation) && UserCrypto.IsUserCryptAvailable)
181+
if (!AWSConfigs.DisableLegacyPersistenceStore && string.IsNullOrEmpty(ProfilesLocation) && UserCrypto.IsUserCryptAvailable)
175182
{
176183
new NetSDKCredentialsFile().RegisterProfile(profile);
177184
}

sdk/src/Core/Amazon.Runtime/Internal/Settings/PersistenceManager.cs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -88,27 +88,26 @@ static PersistenceManager()
8888

8989
try
9090
{
91-
#if BCL
91+
#if NETFRAMEWORK
9292
SettingsStoreFolder = System.Environment.GetFolderPath(System.Environment.SpecialFolder.LocalApplicationData) + "/AWSToolkit";
9393
#else
9494
SettingsStoreFolder = System.Environment.GetEnvironmentVariable("HOME");
9595
if (string.IsNullOrEmpty(SettingsStoreFolder))
9696
SettingsStoreFolder = System.Environment.GetEnvironmentVariable("USERPROFILE");
9797

98-
SettingsStoreFolder = Path.Combine(SettingsStoreFolder, "AppData/Local/AWSToolkit");
98+
SettingsStoreFolder = Path.Combine(SettingsStoreFolder, "AppData", "Local", "AWSToolkit");
9999
#endif
100100
if (!Directory.Exists(SettingsStoreFolder))
101101
Directory.CreateDirectory(SettingsStoreFolder);
102102

103103
Instance = new PersistenceManager();
104104
}
105-
catch (UnauthorizedAccessException ex)
105+
catch (Exception ex) when (ex is UnauthorizedAccessException || ex is IOException)
106106
{
107107
_logger.Error(ex, $"Unable to initialize '{nameof(PersistenceManager)}'. Falling back to '{nameof(InMemoryPersistenceManager)}'.");
108-
109108
Instance = new InMemoryPersistenceManager();
110109
}
111-
}
110+
}
112111

113112
#endregion
114113

sdk/src/Core/Amazon.Util/Internal/RootConfig.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@ public RegionEndpoint RegionEndpoint
5252

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

55+
public bool DisableLegacyPersistenceStore { get; set; }
56+
5557
private const string _rootAwsSectionName = "aws";
5658
public RootConfig()
5759
{
@@ -65,6 +67,7 @@ public RootConfig()
6567
UseSdkCache = AWSConfigs._useSdkCache;
6668
InitializeCollections = AWSConfigs._initializeCollections;
6769
CorrectForClockSkew = true;
70+
DisableLegacyPersistenceStore = AWSConfigs._disableLegacyPersistenceStore;
6871

6972
#if NET8_0_OR_GREATER
7073
DisableDangerousDisablePathAndQueryCanonicalization = AWSConfigs._disableDangerousDisablePathAndQueryCanonicalization;
@@ -105,5 +108,4 @@ public XElement GetServiceSection(string service)
105108
return null;
106109
}
107110
}
108-
109111
}

0 commit comments

Comments
 (0)