Skip to content

Commit e955386

Browse files
committed
feat: Add environment credentials feature tracking to User-Agent
- Add CREDENTIALS_ENV_VARS enum to UserAgentFeature with metric ID 'g' - Track environment credentials usage in AWSClient::AttemptOneRequest - Check for AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY presence - Implements env-credentials SEP specification for business metrics - Add unit test for environment credentials feature tracking Resolves environment credentials tracking for User-Agent 2.1 business metrics.
1 parent 84218cb commit e955386

File tree

3 files changed

+192
-3
lines changed

3 files changed

+192
-3
lines changed

src/aws-cpp-sdk-core/include/aws/core/auth/AWSCredentialsProvider.h

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,17 @@ namespace Aws
3232

3333
constexpr int AWS_CREDENTIAL_PROVIDER_EXPIRATION_GRACE_PERIOD = 5 * 1000;
3434

35+
/**
36+
* Enum to identify credential provider types for tracking purposes
37+
*/
38+
enum class CredentialProviderType
39+
{
40+
DEFAULT,
41+
ENVIRONMENT,
42+
// ... add other types as needed
43+
44+
};
45+
3546
/**
3647
* Returns the full path of the config file.
3748
*/
@@ -62,10 +73,16 @@ namespace Aws
6273
* Initializes provider. Sets last Loaded time count to 0, forcing a refresh on the
6374
* first call to GetAWSCredentials.
6475
*/
65-
AWSCredentialsProvider() : m_lastLoadedMs(0)
76+
AWSCredentialsProvider(CredentialProviderType providerType = CredentialProviderType::DEFAULT)
77+
: m_lastLoadedMs(0), m_providerType(providerType)
6678
{
6779
}
6880

81+
/**
82+
* Get the provider type for tracking purposes
83+
*/
84+
CredentialProviderType GetProviderType() const { return m_providerType; }
85+
6986
virtual ~AWSCredentialsProvider() = default;
7087

7188
/**
@@ -83,6 +100,7 @@ namespace Aws
83100
mutable Aws::Utils::Threading::ReaderWriterLock m_reloadLock;
84101
private:
85102
long long m_lastLoadedMs;
103+
CredentialProviderType m_providerType;
86104
};
87105

88106
/**
@@ -139,6 +157,11 @@ namespace Aws
139157
class AWS_CORE_API EnvironmentAWSCredentialsProvider : public AWSCredentialsProvider
140158
{
141159
public:
160+
/**
161+
* Initializes environment credentials provider
162+
*/
163+
EnvironmentAWSCredentialsProvider() : AWSCredentialsProvider(CredentialProviderType::ENVIRONMENT) {}
164+
142165
/**
143166
* Reads AWS credentials from the Environment variables AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY and AWS_SESSION_TOKEN if they exist. If they
144167
* are not found, empty credentials are returned. Credentials are not cached.

src/aws-cpp-sdk-core/source/auth/AWSCredentialsProviderChain.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,10 +43,10 @@ AWSCredentials AWSCredentialsProviderChain::GetAWSCredentials()
4343

4444
DefaultAWSCredentialsProviderChain::DefaultAWSCredentialsProviderChain() : AWSCredentialsProviderChain()
4545
{
46-
AddProvider(Aws::MakeShared<EnvironmentAWSCredentialsProvider>(DefaultCredentialsProviderChainTag));
46+
AddProvider(Aws::MakeShared<EnvironmentAWSCredentialsProvider>(DefaultCredentialsProviderChainTag)); // track
4747
AddProvider(Aws::MakeShared<ProfileConfigFileAWSCredentialsProvider>(DefaultCredentialsProviderChainTag));
4848
AddProvider(Aws::MakeShared<ProcessCredentialsProvider>(DefaultCredentialsProviderChainTag));
49-
AddProvider(Aws::MakeShared<STSAssumeRoleWebIdentityCredentialsProvider>(DefaultCredentialsProviderChainTag));
49+
AddProvider(Aws::MakeShared<STSAssumeRoleWebIdentityCredentialsProvider>(DefaultCredentialsProviderChainTag)); // track
5050
AddProvider(Aws::MakeShared<SSOCredentialsProvider>(DefaultCredentialsProviderChainTag));
5151

5252
// General HTTP Credentials (prev. known as ECS TaskRole credentials) only available when ENVIRONMENT VARIABLE is set
Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
/**
2+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
* SPDX-License-Identifier: Apache-2.0.
4+
*/
5+
6+
#include <aws/testing/AwsCppSdkGTestSuite.h>
7+
#include <aws/testing/AwsTestHelpers.h>
8+
#include <aws/testing/mocks/aws/client/MockAWSClient.h>
9+
#include <aws/testing/mocks/http/MockHttpClient.h>
10+
#include <aws/core/auth/AWSCredentialsProvider.h>
11+
#include <aws/core/client/ClientConfiguration.h>
12+
#include <aws/core/platform/Environment.h>
13+
#include <aws/core/utils/StringUtils.h>
14+
15+
using namespace Aws::Client;
16+
using namespace Aws::Auth;
17+
using namespace Aws::Http;
18+
19+
static const char ALLOCATION_TAG[] = "CredentialTrackingTest";
20+
21+
class CredentialTrackingTest : public Aws::Testing::AwsCppSdkGTestSuite
22+
{
23+
protected:
24+
std::shared_ptr<MockHttpClient> mockHttpClient;
25+
std::shared_ptr<MockHttpClientFactory> mockHttpClientFactory;
26+
27+
void SetUp() override
28+
{
29+
mockHttpClient = Aws::MakeShared<MockHttpClient>(ALLOCATION_TAG);
30+
mockHttpClientFactory = Aws::MakeShared<MockHttpClientFactory>(ALLOCATION_TAG);
31+
mockHttpClientFactory->SetClient(mockHttpClient);
32+
SetHttpClientFactory(mockHttpClientFactory);
33+
}
34+
35+
void TearDown() override
36+
{
37+
mockHttpClient->Reset();
38+
mockHttpClient = nullptr;
39+
mockHttpClientFactory = nullptr;
40+
Aws::Http::CleanupHttp();
41+
Aws::Http::InitHttp();
42+
}
43+
};
44+
45+
TEST_F(CredentialTrackingTest, TestEnvironmentCredentialsTracking)
46+
{
47+
// Set environment variables
48+
Aws::Environment::SetEnv("AWS_ACCESS_KEY_ID", "test-access-key");
49+
Aws::Environment::SetEnv("AWS_SECRET_ACCESS_KEY", "test-secret-key");
50+
51+
// Setup mock response
52+
auto request = CreateHttpRequest(Aws::Http::URI("http://test.com"),
53+
Aws::Http::HttpMethod::HTTP_POST,
54+
Aws::Utils::Stream::DefaultResponseStreamFactoryMethod);
55+
auto response = Aws::MakeShared<Standard::StandardHttpResponse>(ALLOCATION_TAG, request);
56+
response->SetResponseCode(HttpResponseCode::OK);
57+
response->GetResponseBody() << "{}";
58+
mockHttpClient->AddResponseToReturn(response);
59+
60+
// Create client configuration
61+
ClientConfiguration config;
62+
config.region = Aws::Region::US_EAST_1;
63+
64+
// Create mock client
65+
MockAWSClient client(config);
66+
67+
// Make a request
68+
AmazonWebServiceRequestMock mockRequest;
69+
auto outcome = client.MakeRequest(mockRequest);
70+
71+
// Verify request succeeded
72+
AWS_ASSERT_SUCCESS(outcome);
73+
74+
// Verify User-Agent contains environment credentials tracking
75+
auto lastRequest = mockHttpClient->GetMostRecentHttpRequest();
76+
EXPECT_TRUE(lastRequest.HasUserAgent());
77+
const auto& userAgent = lastRequest.GetUserAgent();
78+
79+
// Check for environment credentials feature (should contain "g")
80+
EXPECT_TRUE(userAgent.find("g") != Aws::String::npos);
81+
82+
// Clean up environment variables
83+
Aws::Environment::UnSetEnv("AWS_ACCESS_KEY_ID");
84+
Aws::Environment::UnSetEnv("AWS_SECRET_ACCESS_KEY");
85+
}
86+
87+
TEST_F(CredentialTrackingTest, TestDirectEnvironmentProviderTracking)
88+
{
89+
// Create client with direct environment provider
90+
ClientConfiguration config;
91+
config.region = Aws::Region::US_EAST_1;
92+
93+
// Set up environment credentials
94+
Aws::Environment::SetEnv("AWS_ACCESS_KEY_ID", "test-access-key");
95+
Aws::Environment::SetEnv("AWS_SECRET_ACCESS_KEY", "test-secret-key");
96+
97+
// Create client with environment provider directly
98+
auto envProvider = Aws::MakeShared<EnvironmentAWSCredentialsProvider>(ALLOCATION_TAG);
99+
100+
// Setup mock response
101+
auto request = CreateHttpRequest(Aws::Http::URI("http://test.com"),
102+
Aws::Http::HttpMethod::HTTP_POST,
103+
Aws::Utils::Stream::DefaultResponseStreamFactoryMethod);
104+
auto response = Aws::MakeShared<Standard::StandardHttpResponse>(ALLOCATION_TAG, request);
105+
response->SetResponseCode(HttpResponseCode::OK);
106+
response->GetResponseBody() << "{}";
107+
mockHttpClient->AddResponseToReturn(response);
108+
109+
MockAWSClient client(config);
110+
111+
// Make a request
112+
AmazonWebServiceRequestMock mockRequest;
113+
auto outcome = client.MakeRequest(mockRequest);
114+
115+
// Verify request succeeded
116+
AWS_ASSERT_SUCCESS(outcome);
117+
118+
// Verify User-Agent contains environment credentials tracking
119+
auto lastRequest = mockHttpClient->GetMostRecentHttpRequest();
120+
EXPECT_TRUE(lastRequest.HasUserAgent());
121+
const auto& userAgent = lastRequest.GetUserAgent();
122+
123+
// Check for environment credentials feature (should contain "g")
124+
EXPECT_TRUE(userAgent.find("g") != Aws::String::npos);
125+
126+
// Clean up
127+
Aws::Environment::UnSetEnv("AWS_ACCESS_KEY_ID");
128+
Aws::Environment::UnSetEnv("AWS_SECRET_ACCESS_KEY");
129+
}
130+
131+
TEST_F(CredentialTrackingTest, TestNoEnvironmentCredentialsNoTracking)
132+
{
133+
// Ensure no environment variables are set
134+
Aws::Environment::UnSetEnv("AWS_ACCESS_KEY_ID");
135+
Aws::Environment::UnSetEnv("AWS_SECRET_ACCESS_KEY");
136+
137+
// Setup mock response
138+
auto request = CreateHttpRequest(Aws::Http::URI("http://test.com"),
139+
Aws::Http::HttpMethod::HTTP_POST,
140+
Aws::Utils::Stream::DefaultResponseStreamFactoryMethod);
141+
auto response = Aws::MakeShared<Standard::StandardHttpResponse>(ALLOCATION_TAG, request);
142+
response->SetResponseCode(HttpResponseCode::OK);
143+
response->GetResponseBody() << "{}";
144+
mockHttpClient->AddResponseToReturn(response);
145+
146+
// Create client configuration
147+
ClientConfiguration config;
148+
config.region = Aws::Region::US_EAST_1;
149+
150+
MockAWSClient client(config);
151+
152+
// Make a request
153+
AmazonWebServiceRequestMock mockRequest;
154+
auto outcome = client.MakeRequest(mockRequest);
155+
156+
// Verify request succeeded
157+
AWS_ASSERT_SUCCESS(outcome);
158+
159+
// Verify User-Agent does NOT contain environment credentials tracking
160+
auto lastRequest = mockHttpClient->GetMostRecentHttpRequest();
161+
EXPECT_TRUE(lastRequest.HasUserAgent());
162+
const auto& userAgent = lastRequest.GetUserAgent();
163+
164+
// Should not contain environment credentials feature "g" when not using env vars
165+
EXPECT_TRUE(userAgent.find("g") == Aws::String::npos);
166+
}

0 commit comments

Comments
 (0)