77#include < aws/testing/AwsTestHelpers.h>
88#include < aws/testing/mocks/aws/client/MockAWSClient.h>
99#include < aws/testing/mocks/http/MockHttpClient.h>
10+ #include < aws/testing/mocks/aws/auth/MockAWSHttpResourceClient.h>
1011#include < aws/testing/platform/PlatformTesting.h>
1112#include < aws/core/auth/AWSCredentialsProvider.h>
1213#include < aws/core/auth/AWSCredentialsProviderChain.h>
1314#include < aws/core/client/AWSClient.h>
1415#include < aws/core/utils/StringUtils.h>
16+ #include < aws/core/utils/HashingUtils.h>
17+ #include < aws/core/platform/FileSystem.h>
18+ #include < aws/core/utils/FileSystemUtils.h>
19+ #include < fstream>
20+ #include < sys/stat.h>
1521
1622using namespace Aws ::Client;
1723using namespace Aws ::Auth;
1824using namespace Aws ::Http;
1925
20- static const char ALLOCATION_TAG[] = " CredentialTrackingTest" ;
26+ namespace {
27+ const char * TEST_LOG_TAG = " CredentialTrackingTest" ;
28+ }
29+
30+ static Aws::String WrapEchoStringWithSingleQuoteForUnixShell (Aws::String str)
31+ {
32+ #ifndef _WIN32
33+ str.insert (0 , 1 , ' \' ' );
34+ str.append (1 , ' \' ' );
35+ #endif
36+ return str;
37+ }
2138
2239// Custom client that uses default credential provider for testing
2340class CredentialTestingClient : public Aws ::Client::AWSClient
2441{
2542public:
2643 explicit CredentialTestingClient (const Aws::Client::ClientConfiguration& configuration)
2744 : AWSClient(configuration,
28- Aws::MakeShared<Aws::Client::AWSAuthV4Signer>(ALLOCATION_TAG ,
29- Aws::MakeShared<DefaultAWSCredentialsProviderChain>(ALLOCATION_TAG ),
45+ Aws::MakeShared<Aws::Client::AWSAuthV4Signer>(TEST_LOG_TAG ,
46+ Aws::MakeShared<DefaultAWSCredentialsProviderChain>(TEST_LOG_TAG ),
3047 "service", configuration.region),
31- Aws::MakeShared<MockAWSErrorMarshaller>(ALLOCATION_TAG))
48+ Aws::MakeShared<MockAWSErrorMarshaller>(TEST_LOG_TAG))
49+ {
50+ }
51+
52+ // Constructor with custom credential provider for IMDS test
53+ explicit CredentialTestingClient (const Aws::Client::ClientConfiguration& configuration,
54+ std::shared_ptr<AWSCredentialsProvider> credentialsProvider)
55+ : AWSClient(configuration,
56+ Aws::MakeShared<Aws::Client::AWSAuthV4Signer>(TEST_LOG_TAG,
57+ credentialsProvider,
58+ " service" , configuration.region),
59+ Aws::MakeShared<MockAWSErrorMarshaller>(TEST_LOG_TAG))
3260 {
3361 }
3462
@@ -56,8 +84,8 @@ class CredentialTrackingTest : public Aws::Testing::AwsCppSdkGTestSuite
5684
5785 void SetUp () override
5886 {
59- mockHttpClient = Aws::MakeShared<MockHttpClient>(ALLOCATION_TAG );
60- mockHttpClientFactory = Aws::MakeShared<MockHttpClientFactory>(ALLOCATION_TAG );
87+ mockHttpClient = Aws::MakeShared<MockHttpClient>(TEST_LOG_TAG );
88+ mockHttpClientFactory = Aws::MakeShared<MockHttpClientFactory>(TEST_LOG_TAG );
6189 mockHttpClientFactory->SetClient (mockHttpClient);
6290 SetHttpClientFactory (mockHttpClientFactory);
6391 }
@@ -70,6 +98,56 @@ class CredentialTrackingTest : public Aws::Testing::AwsCppSdkGTestSuite
7098 Aws::Http::CleanupHttp ();
7199 Aws::Http::InitHttp ();
72100 }
101+
102+ void RunTestWithCredentialsProvider (const std::shared_ptr<AWSCredentialsProvider>& credentialsProvider, const Aws::String& id) {
103+ // Setup mock response
104+ std::shared_ptr<HttpRequest> requestTmp =
105+ CreateHttpRequest (Aws::Http::URI (" dummy" ), Aws::Http::HttpMethod::HTTP_POST,
106+ Aws::Utils::Stream::DefaultResponseStreamFactoryMethod);
107+ auto successResponse = Aws::MakeShared<Standard::StandardHttpResponse>(TEST_LOG_TAG, requestTmp);
108+ successResponse->SetResponseCode (HttpResponseCode::OK);
109+ successResponse->GetResponseBody () << " {}" ;
110+ mockHttpClient->AddResponseToReturn (successResponse);
111+
112+ // Create client configuration
113+ Aws::Client::ClientConfigurationInitValues cfgInit;
114+ cfgInit.shouldDisableIMDS = true ;
115+ Aws::Client::ClientConfiguration clientConfig (cfgInit);
116+ clientConfig.region = Aws::Region::US_EAST_1;
117+
118+ // Create credential testing client that uses default provider chain
119+ CredentialTestingClient client (clientConfig, credentialsProvider);
120+
121+ // Create mock request
122+ AmazonWebServiceRequestMock mockRequest;
123+
124+ // Make request
125+ auto outcome = client.MakeRequest (mockRequest);
126+ ASSERT_TRUE (outcome.IsSuccess ());
127+
128+ // Verify User-Agent contains environment credentials tracking
129+ auto lastRequest = mockHttpClient->GetMostRecentHttpRequest ();
130+ EXPECT_TRUE (lastRequest.HasHeader (Aws::Http::USER_AGENT_HEADER));
131+ const auto & userAgent = lastRequest.GetHeaderValue (Aws::Http::USER_AGENT_HEADER);
132+ EXPECT_FALSE (userAgent.empty ());
133+
134+ const auto userAgentParsed = Aws::Utils::StringUtils::Split (userAgent, ' ' );
135+
136+ // Verify there's only one m/ section (no duplicate m/ sections)
137+ int mSectionCount = 0 ;
138+ for (const auto & part : userAgentParsed) {
139+ if (part.find (" m/" ) != Aws::String::npos) {
140+ mSectionCount ++;
141+ }
142+ }
143+ EXPECT_EQ (1 , mSectionCount );
144+
145+ // Check for environment credentials business metric (g) in user agent
146+ auto businessMetrics = std::find_if (userAgentParsed.begin (), userAgentParsed.end (),
147+ [&id](const Aws::String& value) { return value.find (" m/" ) != Aws::String::npos && value.find (id) != Aws::String::npos; });
148+
149+ EXPECT_TRUE (businessMetrics != userAgentParsed.end ());
150+ }
73151};
74152
75153TEST_F (CredentialTrackingTest, TestEnvironmentCredentialsTracking)
@@ -78,52 +156,61 @@ TEST_F(CredentialTrackingTest, TestEnvironmentCredentialsTracking)
78156 {" AWS_ACCESS_KEY_ID" , " test-access-key" },
79157 {" AWS_SECRET_ACCESS_KEY" , " test-secret-key" },
80158 }};
159+ auto credsProvider = Aws::MakeShared<Aws::Auth::EnvironmentAWSCredentialsProvider>(TEST_LOG_TAG);
160+ RunTestWithCredentialsProvider (std::move (credsProvider), " g" );
161+ }
81162
82- // Setup mock response
83- std::shared_ptr<HttpRequest> requestTmp =
84- CreateHttpRequest (Aws::Http::URI (" dummy" ), Aws::Http::HttpMethod::HTTP_POST,
85- Aws::Utils::Stream::DefaultResponseStreamFactoryMethod);
86- auto successResponse = Aws::MakeShared<Standard::StandardHttpResponse>(ALLOCATION_TAG, requestTmp);
87- successResponse->SetResponseCode (HttpResponseCode::OK);
88- successResponse->GetResponseBody () << " {}" ;
89- mockHttpClient->AddResponseToReturn (successResponse);
90-
91- // Create client configuration
92- Aws::Client::ClientConfigurationInitValues cfgInit;
93- cfgInit.shouldDisableIMDS = true ;
94- Aws::Client::ClientConfiguration clientConfig (cfgInit);
95- clientConfig.region = Aws::Region::US_EAST_1;
96-
97- // Create credential testing client that uses default provider chain
98- CredentialTestingClient client (clientConfig);
99-
100- // Create mock request
101- AmazonWebServiceRequestMock mockRequest;
102-
103- // Make request
104- auto outcome = client.MakeRequest (mockRequest);
105- ASSERT_TRUE (outcome.IsSuccess ());
106-
107- // Verify User-Agent contains environment credentials tracking
108- auto lastRequest = mockHttpClient->GetMostRecentHttpRequest ();
109- EXPECT_TRUE (lastRequest.HasHeader (Aws::Http::USER_AGENT_HEADER));
110- const auto & userAgent = lastRequest.GetHeaderValue (Aws::Http::USER_AGENT_HEADER);
111- EXPECT_FALSE (userAgent.empty ());
112-
113- const auto userAgentParsed = Aws::Utils::StringUtils::Split (userAgent, ' ' );
114-
115- // Verify there's only one m/ section (no duplicate m/ sections)
116- int mSectionCount = 0 ;
117- for (const auto & part : userAgentParsed) {
118- if (part.find (" m/" ) != Aws::String::npos) {
119- mSectionCount ++;
120- }
121- }
122- EXPECT_EQ (1 , mSectionCount );
163+ TEST_F (CredentialTrackingTest, TestProfileCredentialsTracking)
164+ {
165+ // Create temporary credentials file
166+ Aws::Utils::TempFile credentialsFile (std::ios_base::out | std::ios_base::trunc);
167+ ASSERT_TRUE (credentialsFile.good ());
168+ credentialsFile << " [default]" << std::endl;
169+ credentialsFile << " aws_access_key_id = test-profile-access-key" << std::endl;
170+ credentialsFile << " aws_secret_access_key = test-profile-secret-key" << std::endl;
171+ credentialsFile.close ();
172+
173+ // Set environment to use our test credentials file
174+ Aws::Environment::EnvironmentRAII testEnvironment{{
175+ {" AWS_SHARED_CREDENTIALS_FILE" , credentialsFile.GetFileName ().c_str ()},
176+ }};
177+ Aws::Config::ReloadCachedCredentialsFile ();
123178
124- // Check for environment credentials business metric (g) in user agent
125- auto businessMetrics = std::find_if (userAgentParsed. begin ( ), userAgentParsed. end (),
126- []( const Aws::String& value) { return value. find ( " m/ " ) != Aws::String::npos && value. find ( " g " ) != Aws::String::npos; });
179+ auto credsProvider = Aws::MakeShared<Aws::Auth::ProfileConfigFileAWSCredentialsProvider>(TEST_LOG_TAG);
180+ RunTestWithCredentialsProvider ( std::move (credsProvider ), " n " );
181+ }
127182
128- EXPECT_TRUE (businessMetrics != userAgentParsed.end ());
183+ TEST_F (CredentialTrackingTest, TestProfileProcessCredentialsTracking)
184+ {
185+ // Create temporary config file with credential_process
186+ Aws::Utils::TempFile configFile (std::ios_base::out | std::ios_base::trunc);
187+ ASSERT_TRUE (configFile.good ());
188+ configFile << " [default]" << std::endl;
189+ configFile << " credential_process = echo " << WrapEchoStringWithSingleQuoteForUnixShell (" {\" Version\" : 1, \" AccessKeyId\" : \" test-process-key\" , \" SecretAccessKey\" : \" test-process-secret\" }" ) << std::endl;
190+ configFile.close ();
191+
192+ // Set environment to use our test config file
193+ Aws::Environment::EnvironmentRAII testEnvironment{{
194+ {" AWS_CONFIG_FILE" , configFile.GetFileName ().c_str ()},
195+ }};
196+
197+ // Force reload config file after setting environment variable
198+ Aws::Config::ReloadCachedConfigFile ();
199+
200+ auto credsProvider = Aws::MakeShared<Aws::Auth::ProcessCredentialsProvider>(TEST_LOG_TAG);
201+ RunTestWithCredentialsProvider (std::move (credsProvider), " v" );
129202}
203+
204+ TEST_F (CredentialTrackingTest, TestInstanceProfileCredentialsTracking)
205+ {
206+ // Create mock EC2 metadata client with valid credentials
207+ auto mockClient = Aws::MakeShared<MockEC2MetadataClient>(TEST_LOG_TAG);
208+ const char * validCredentials = R"( { "AccessKeyId": "test-imds-access-key", "SecretAccessKey": "test-imds-secret-key", "Token": "test-imds-token", "Code": "Success", "Expiration": "2037-04-19T00:00:00Z" })" ;
209+ mockClient->SetMockedCredentialsValue (validCredentials);
210+
211+ // Create IMDS credential provider with mock client
212+ auto imdsProvider = Aws::MakeShared<InstanceProfileCredentialsProvider>(TEST_LOG_TAG,
213+ Aws::MakeShared<Aws::Config::EC2InstanceProfileConfigLoader>(TEST_LOG_TAG, mockClient), 1000 );
214+
215+ RunTestWithCredentialsProvider (std::move (imdsProvider), " 0" );
216+ }
0 commit comments