Skip to content

Commit 7dd7cca

Browse files
authored
Add option to overwrite credential search order
1 parent 7f0527b commit 7dd7cca

File tree

5 files changed

+75
-66
lines changed

5 files changed

+75
-66
lines changed
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"core": {
3+
"updateMinimum": true,
4+
"type": "Patch",
5+
"changeLogMessages": [
6+
"Add `AWSConfigs.AWSCredentialsGenerators` option so that a custom credential resolution order can be specified globally (matching the behavior from `FallbackCredentialsFactory.CredentialsGenerators`)"
7+
]
8+
}
9+
}

sdk/src/Core/AWSConfigs.cs

Lines changed: 31 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
using System.Collections.Generic;
2929
using Amazon.Runtime;
3030
using Amazon.Runtime.Telemetry;
31+
using Amazon.Runtime.Credentials;
3132

3233
namespace Amazon
3334
{
@@ -72,32 +73,23 @@ public static partial class AWSConfigs
7273
{
7374
#region Private static members
7475

75-
private static char[] validSeparators = new char[] { ' ', ',' };
76-
7776
// Tests can override this DateTime source.
7877
internal static Func<DateTime> utcNowSource = GetUtcNow;
7978

80-
// Deprecated configs
8179
internal static string _awsRegion = GetConfig(AWSRegionKey);
8280
internal static string _awsProfileName = GetConfig(AWSProfileNameKey);
8381
internal static string _awsAccountsLocation = GetConfig(AWSProfilesLocationKey);
8482
internal static bool _useSdkCache = GetConfigBool(UseSdkCacheKey, defaultValue: true);
8583
internal static bool _initializeCollections = GetConfigBool(InitializeCollectionsKey, defaultValue: false);
86-
// for reading from awsconfigs.xml
87-
private static object _lock = new object();
88-
private static List<string> standardConfigs = new List<string>() { "region", "logging", "correctForClockSkew" };
8984
private static TelemetryProvider _telemetryProvider = new DefaultTelemetryProvider();
9085

91-
#pragma warning disable 414
92-
private static bool configPresent = true;
93-
#pragma warning restore 414
94-
9586
#if NET8_0_OR_GREATER
9687
internal static bool _disableDangerousDisablePathAndQueryCanonicalization = GetConfigBool(DisableDangerousDisablePathAndQueryCanonicalizationKey, defaultValue: false);
9788
#endif
9889

9990
// New config section
100-
private static RootConfig _rootConfig = new RootConfig();
91+
private static readonly RootConfig _rootConfig = new();
92+
10193
#endregion
10294

10395
#region Clock Skew
@@ -226,12 +218,12 @@ public static string AWSProfilesLocation
226218

227219
/// <summary>
228220
/// Key for the StreamingUtf8JsonReaderBufferSize property.
229-
/// <seealso cref="Amazon.AWSConfigs.StreamingUtf8JsonReaderBufferSize"/>"/>
221+
/// <seealso cref="StreamingUtf8JsonReaderBufferSize"/>
230222
/// </summary>
231223
public const string StreamingUtf8JsonReaderBufferSizeKey = "StreamingUtf8JsonReaderBufferSize";
232224

233225
/// <summary>
234-
/// Configures the default buffer size for the the StreamingUtf8JsonReader/>
226+
/// Configures the default buffer size for the the StreamingUtf8JsonReader
235227
/// used for buffering data from the stream passed into its constructor. If this isn't set, the SDK will default to 4096 bytes.
236228
///
237229
/// Setting this property is not thread safe and should only be set at application startup.
@@ -324,7 +316,32 @@ public static bool DisableDangerousDisablePathAndQueryCanonicalization
324316
set { _rootConfig.DisableDangerousDisablePathAndQueryCanonicalization = value; }
325317
}
326318
#endif
327-
#endregion
319+
#endregion
320+
321+
#region CredentialsGenerators
322+
323+
/// <summary>
324+
/// Global configuration option to override the search order for credentials when creating SDK service clients without credentials.
325+
/// <para />
326+
/// This option is equivalent to the <see cref="FallbackCredentialsFactory.CredentialsGenerators"/>, but it should only be used
327+
/// if the <a href="https://docs.aws.amazon.com/sdk-for-net/v4/developer-guide/creds-assign.html">default order</a> does not meet your application needs.
328+
/// <para />
329+
/// When set, all service clients will use the specified providers so you must guarantee they return valid
330+
/// credentials for the operations to succeed.
331+
/// <para />
332+
/// Setting this property is not thread safe and should only be set at application startup.
333+
/// </summary>
334+
/// <remarks>
335+
/// This option is only used in the <see cref="DefaultAWSCredentialsIdentityResolver"/>, it's not considered by the
336+
/// deprecated <see cref="FallbackCredentialsFactory"/> when resolving credentials.
337+
/// </remarks>
338+
public static List<DefaultAWSCredentialsIdentityResolver.CredentialsGenerator> AWSCredentialsGenerators
339+
{
340+
get { return _rootConfig.AWSCredentialsGenerators; }
341+
set { _rootConfig.AWSCredentialsGenerators = value; }
342+
}
343+
344+
#endregion
328345

329346
#region AWS Config Sections
330347

@@ -462,48 +479,6 @@ private static bool GetConfigBool(string name, bool defaultValue = false)
462479
return defaultValue;
463480
}
464481

465-
private static T GetConfigEnum<T>(string name)
466-
{
467-
var type = typeof(T);
468-
if (!type.IsEnum) throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, "Type {0} must be enum", type.FullName));
469-
470-
string value = GetConfig(name);
471-
if (string.IsNullOrEmpty(value))
472-
return default(T);
473-
T result = ParseEnum<T>(value);
474-
return result;
475-
}
476-
477-
private static T ParseEnum<T>(string value)
478-
{
479-
T t;
480-
if (TryParseEnum<T>(value, out t))
481-
return t;
482-
Type type = typeof(T);
483-
string messageFormat = "Unable to parse value {0} as enum of type {1}. Valid values are: {2}";
484-
string enumNames = string.Join(", ", Enum.GetNames(type));
485-
throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, messageFormat, value, type.FullName, enumNames));
486-
}
487-
488-
private static bool TryParseEnum<T>(string value, out T result)
489-
{
490-
result = default(T);
491-
492-
if (string.IsNullOrEmpty(value))
493-
return false;
494-
495-
try
496-
{
497-
T t = (T)Enum.Parse(typeof(T), value, true);
498-
result = t;
499-
return true;
500-
}
501-
catch (ArgumentException)
502-
{
503-
return false;
504-
}
505-
}
506-
507482
/// <summary>
508483
/// This method should never be called directly.
509484
/// Call AWSSDKUtils.CorrectedUtcNow instead.

sdk/src/Core/Amazon.Runtime/Credentials/DefaultAWSCredentialsIdentityResolver.cs

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,28 +27,35 @@
2727
namespace Amazon.Runtime.Credentials
2828
{
2929
/// <summary>
30-
/// A resolver that provides an AWSCredentials identity.
30+
/// A resolver that provides an <see cref="AWSCredentials"/> identity.
31+
/// <para />
32+
/// The default search order used is described in the <a href="https://docs.aws.amazon.com/sdk-for-net/v4/developer-guide/creds-assign.html">
33+
/// developer guide</a>, but it can be overwritten by setting the <see cref="AWSConfigs.AWSCredentialsGenerators"/> property.
3134
/// </summary>
3235
public class DefaultAWSCredentialsIdentityResolver : IIdentityResolver<AWSCredentials>
3336
{
3437
private const string AWS_PROFILE_ENVIRONMENT_VARIABLE = "AWS_PROFILE";
3538
private const string DEFAULT_PROFILE_NAME = "default";
3639

40+
/// <summary>
41+
/// A method that should either return valid <see cref="AWSCredentials"/> or throw an exception (so
42+
/// that the SDK can move on and attempt the next generator in the credential chain).
43+
/// </summary>
44+
public delegate AWSCredentials CredentialsGenerator();
45+
3746
private static readonly ReaderWriterLockSlim _cachedCredentialsLock = new();
38-
private delegate AWSCredentials CredentialsGenerator();
3947
private AWSCredentials _cachedCredentials;
4048
private readonly List<CredentialsGenerator> _credentialsGenerators;
4149
private readonly CredentialProfileStoreChain _credentialProfileChain = new();
4250
private readonly EnvironmentState _lastKnownEnvironmentState = new();
43-
44-
private static readonly Lazy<DefaultAWSCredentialsIdentityResolver> _defaultInstance = new Lazy<DefaultAWSCredentialsIdentityResolver>();
51+
private static readonly Lazy<DefaultAWSCredentialsIdentityResolver> _defaultInstance = new();
4552

4653
public DefaultAWSCredentialsIdentityResolver()
4754
{
4855
_cachedCredentials = null;
4956
_credentialsGenerators = new List<CredentialsGenerator>
5057
{
51-
#if BCL
58+
#if NETFRAMEWORK
5259
() => new AppConfigAWSCredentials(), // Test explicit keys/profile name first.
5360
#endif
5461
() => new EnvironmentVariablesAWSCredentials(), // Look for credentials set in environment vars.
@@ -144,8 +151,19 @@ private AWSCredentials InternalGetCredentials()
144151
return _cachedCredentials;
145152
}
146153

154+
List<CredentialsGenerator> providersToUse;
155+
if (AWSConfigs.AWSCredentialsGenerators != null)
156+
{
157+
Logger.GetLogger(typeof(DefaultAWSCredentialsIdentityResolver)).DebugFormat("Using custom credential search order defined in {0}", nameof(AWSConfigs));
158+
providersToUse = AWSConfigs.AWSCredentialsGenerators;
159+
}
160+
else
161+
{
162+
providersToUse = _credentialsGenerators;
163+
}
164+
147165
List<Exception> errors = new List<Exception>();
148-
foreach (CredentialsGenerator generator in _credentialsGenerators)
166+
foreach (CredentialsGenerator generator in providersToUse)
149167
{
150168
try
151169
{

sdk/src/Core/Amazon.Runtime/Credentials/FallbackCredentialsFactory.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
* permissions and limitations under the License.
1414
*/
1515
using Amazon.Runtime.CredentialManagement;
16+
using Amazon.Runtime.Credentials;
1617
using Amazon.Runtime.Internal.Util;
1718
using System;
1819
using System.Collections.Generic;
@@ -40,6 +41,13 @@ static FallbackCredentialsFactory()
4041
}
4142

4243
public delegate AWSCredentials CredentialsGenerator();
44+
45+
/// <summary>
46+
/// When migrating to version 4 of the SDK the <see cref="DefaultAWSCredentialsIdentityResolver"/> will be the default identity resolver.
47+
/// Changing this property will not affect global override for the default credential provider chain.
48+
/// <para />
49+
/// To change the default credential provider chain use the the <see cref="AWSConfigs.AWSCredentialsGenerators"/> property.
50+
/// </summary>
4351
public static List<CredentialsGenerator> CredentialsGenerators { get; set; }
4452

4553
public static void Reset()

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

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,7 @@
1-
using System;
1+
using Amazon.Runtime.Credentials;
22
using System.Collections.Generic;
3-
using System.Linq;
4-
using System.Text;
53
using System.Xml.Linq;
64

7-
85
namespace Amazon.Util.Internal
96
{
107
/// <summary>
@@ -53,6 +50,8 @@ public RegionEndpoint RegionEndpoint
5350
public bool DisableDangerousDisablePathAndQueryCanonicalization { get; set; }
5451
#endif
5552

53+
public List<DefaultAWSCredentialsIdentityResolver.CredentialsGenerator> AWSCredentialsGenerators { get; set; }
54+
5655
private const string _rootAwsSectionName = "aws";
5756
public RootConfig()
5857
{

0 commit comments

Comments
 (0)