Skip to content

Commit 0d0a337

Browse files
committedNov 5, 2024
Fixes issue #3479 where S3ForcePathStyle is unable to be read from a credential profile
1 parent ad13fd4 commit 0d0a337

File tree

5 files changed

+158
-5
lines changed

5 files changed

+158
-5
lines changed
 
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
{
2+
"core": {
3+
"changeLogMessages": [
4+
"Add S3ForcePathStyle as a config option for credential profiles."
5+
],
6+
"type": "patch",
7+
"updateMinimum": true
8+
},
9+
"services": [
10+
{
11+
"serviceName": "S3",
12+
"type": "patch",
13+
"changeLogMessages": [
14+
"Fixes [issue 3479](https://github.com/aws/aws-sdk-net/issues/3479) where ForcePathStyle is unable to be read from the config file"
15+
]
16+
}
17+
]
18+
}

‎sdk/src/Core/Amazon.Runtime/CredentialManagement/CredentialProfile.cs

+5
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,11 @@ internal Dictionary<string, Dictionary<string, string>> NestedProperties
9393
/// If true, the use of multi-region access points is disabled.
9494
/// </summary>
9595
public bool? S3DisableMultiRegionAccessPoints { get; set; }
96+
97+
/// <summary>
98+
/// When true, S3 requests will always use path style addressing.
99+
/// </summary>
100+
public bool? S3ForcePathStyle { get; set; }
96101

97102
/// <summary>
98103
/// The Sts Regional Endpoints Value as either legacy or regional

‎sdk/src/Core/Amazon.Runtime/CredentialManagement/SharedCredentialsFile.cs

+24-2
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ public class SharedCredentialsFile : ICredentialProfileStore
7171
private const string RequestMinCompressionSizeBytesField = "request_min_compression_size_bytes";
7272
private const string ClientAppIdField = "sdk_ua_app_id";
7373
private const string AccountIdEndpointModeField = "account_id_endpoint_mode";
74+
private const string S3ForcePathStyleField = "s3_force_path_style";
7475
private readonly Logger _logger = Logger.GetLogger(typeof(SharedCredentialsFile));
7576

7677
private static readonly HashSet<string> ReservedPropertyNames = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
@@ -104,7 +105,8 @@ public class SharedCredentialsFile : ICredentialProfileStore
104105
DisableRequestCompressionField,
105106
RequestMinCompressionSizeBytesField,
106107
ClientAppIdField,
107-
AccountIdEndpointModeField
108+
AccountIdEndpointModeField,
109+
S3ForcePathStyleField
108110
};
109111

110112
/// <summary>
@@ -443,9 +445,13 @@ private void RegisterProfileInternal(CredentialProfile profile)
443445

444446
if (profile.ClientAppId != null)
445447
reservedProperties[ClientAppIdField] = profile.ClientAppId;
448+
446449
if (profile.AccountIdEndpointMode != null)
447450
reservedProperties[AccountIdEndpointModeField] = profile.AccountIdEndpointMode.ToString().ToLowerInvariant();
448451

452+
if (profile.S3ForcePathStyle != null)
453+
reservedProperties[S3ForcePathStyleField] = profile.S3ForcePathStyle.ToString().ToLowerInvariant();
454+
449455
var profileDictionary = PropertyMapping.CombineProfileParts(
450456
profile.Options, ReservedPropertyNames, reservedProperties, profile.Properties);
451457

@@ -966,6 +972,21 @@ private bool TryGetProfile(string profileName, bool doRefresh, bool isSsoSession
966972

967973
#endif
968974
}
975+
976+
string s3ForcePathStyleString;
977+
bool? s3ForcePathStyle = null;
978+
if (reservedProperties.TryGetValue(S3ForcePathStyleField, out s3ForcePathStyleString))
979+
{
980+
bool s3ForcePathStyleOut;
981+
if (!bool.TryParse(s3ForcePathStyleString, out s3ForcePathStyleOut))
982+
{
983+
Logger.GetLogger(GetType()).InfoFormat("Invalid value {0} for {1} in profile {2}. A boolean true/false is expected.", s3ForcePathStyleString, S3ForcePathStyleField, profileName);
984+
profile = null;
985+
return false;
986+
}
987+
s3ForcePathStyle = s3ForcePathStyleOut;
988+
}
989+
969990
profile = new CredentialProfile(profileName, profileOptions)
970991
{
971992
UniqueKey = toolkitArtifactGuid,
@@ -992,7 +1013,8 @@ private bool TryGetProfile(string profileName, bool doRefresh, bool isSsoSession
9921013
DisableRequestCompression = disableRequestCompression,
9931014
RequestMinCompressionSizeBytes = requestMinCompressionSizeBytes,
9941015
ClientAppId = clientAppId,
995-
AccountIdEndpointMode = accountIdEndpointMode
1016+
AccountIdEndpointMode = accountIdEndpointMode,
1017+
S3ForcePathStyle = s3ForcePathStyle
9961018
};
9971019

9981020
if (!IsSupportedProfileType(profile.ProfileType))

‎sdk/src/Services/S3/Custom/AmazonS3Config.cs

+30-3
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ public partial class AmazonS3Config : ClientConfig
3636
private const string AwsS3UsEast1RegionalEndpointsEnvironmentVariable = "AWS_S3_US_EAST_1_REGIONAL_ENDPOINT";
3737
private const string DisableMRAPEnvName = "AWS_S3_DISABLE_MULTIREGION_ACCESS_POINTS";
3838

39-
private bool forcePathStyle = false;
39+
private bool? _forcePathStyle;
4040
private bool useAccelerateEndpoint = false;
4141
private S3UsEast1RegionalEndpointValue? s3UsEast1RegionalEndpointValue;
4242
private readonly string legacyUSEast1GlobalRegionSystemName = RegionEndpoint.USEast1.SystemName;
@@ -61,13 +61,40 @@ public IS3ExpressCredentialProvider S3ExpressCredentialProvider
6161
set { s3ExpressCredentialProvider = value; }
6262
}
6363

64+
private object _forcePathStyleLock = new object();
6465
/// <summary>
6566
/// When true, requests will always use path style addressing.
6667
/// </summary>
6768
public bool ForcePathStyle
6869
{
69-
get { return forcePathStyle; }
70-
set { forcePathStyle = value; }
70+
get
71+
{
72+
if (_forcePathStyle.HasValue)
73+
{
74+
return _forcePathStyle.GetValueOrDefault();
75+
}
76+
77+
ResolveCredentialProfile();
78+
79+
lock (_forcePathStyleLock)
80+
{
81+
if (_forcePathStyle.HasValue)
82+
{
83+
return _forcePathStyle.Value;
84+
}
85+
86+
_forcePathStyle = _profile?.S3ForcePathStyle;
87+
return _forcePathStyle.GetValueOrDefault();
88+
}
89+
}
90+
91+
set
92+
{
93+
lock (_forcePathStyleLock)
94+
{
95+
_forcePathStyle = value;
96+
}
97+
}
7198
}
7299

73100
/// <summary>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
using Amazon.S3;
2+
using Microsoft.VisualStudio.TestTools.UnitTesting;
3+
using System;
4+
using System.IO;
5+
using AWSSDK_DotNet.CommonTest.Utils;
6+
using Amazon.Runtime.CredentialManagement;
7+
8+
namespace AWSSDK.UnitTests
9+
{
10+
[TestClass]
11+
public class S3ForcePathStyleTests
12+
{
13+
private static readonly string ProfileText =
14+
@"[enable_force_path_style]
15+
region = us-west-2
16+
aws_access_key_id = default_aws_access_key_id
17+
aws_secret_access_key = default_aws_secret_access_key
18+
s3_force_path_style = true
19+
[disable_force_path_style]
20+
region = us-west-2
21+
aws_access_key_id = other_aws_access_key_id
22+
aws_secret_access_key = other_aws_secret_access_key
23+
s3_force_path_style = false";
24+
25+
private const string AWSProfileVariable = "AWS_PROFILE";
26+
private string _beginningAWSProfileEnvironmentValue;
27+
private string _tempCredentialsFilePath;
28+
29+
[TestInitialize]
30+
public void Initialize()
31+
{
32+
// Save off current environment variable value to restore later
33+
_beginningAWSProfileEnvironmentValue = Environment.GetEnvironmentVariable(AWSProfileVariable);
34+
35+
// Then clear the current value so every test is starting from a clean slate
36+
Environment.SetEnvironmentVariable(AWSProfileVariable, "");
37+
38+
// set credentials file and use it to load CredentialProfileStoreChain
39+
_tempCredentialsFilePath = Path.GetTempFileName();
40+
File.WriteAllText(_tempCredentialsFilePath, ProfileText);
41+
ReflectionHelpers.Invoke(typeof(AmazonS3Config), "credentialProfileChain", new CredentialProfileStoreChain(_tempCredentialsFilePath));
42+
ReflectionHelpers.Invoke(typeof(AmazonS3Config), "_triedToResolveProfile", false);
43+
}
44+
45+
[TestCleanup]
46+
public void RestoreOriginalSettings()
47+
{
48+
Environment.SetEnvironmentVariable(AWSProfileVariable, _beginningAWSProfileEnvironmentValue);
49+
File.Delete(_tempCredentialsFilePath);
50+
}
51+
52+
[TestMethod]
53+
[TestCategory("S3")]
54+
public void CredentialProfileEnable_ShouldApplyToS3Config()
55+
{
56+
Environment.SetEnvironmentVariable(AWSProfileVariable, "enable_force_path_style");
57+
var config = new AmazonS3Config();
58+
Assert.IsTrue(config.ForcePathStyle);
59+
}
60+
61+
[TestMethod]
62+
[TestCategory("S3")]
63+
public void UnsetForcePathStyleShouldDefaultToFalse()
64+
{
65+
var config = new AmazonS3Config();
66+
Assert.IsFalse(config.ForcePathStyle);
67+
}
68+
69+
[TestMethod]
70+
[TestCategory("S3")]
71+
public void ConfigShouldOverrideProfile()
72+
{
73+
Environment.SetEnvironmentVariable(AWSProfileVariable, "enable_force_path_style");
74+
var config = new AmazonS3Config
75+
{
76+
ForcePathStyle = false
77+
};
78+
Assert.IsFalse(config.ForcePathStyle);
79+
}
80+
}
81+
}

0 commit comments

Comments
 (0)
Failed to load comments.