Skip to content

Commit db53b07

Browse files
committed
Implement feature IDs:
-S3Express, S3AccessGrants, IMDS Credentials
1 parent c241f5e commit db53b07

File tree

12 files changed

+1481
-1
lines changed

12 files changed

+1481
-1
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
/*
2+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License").
5+
* You may not use this file except in compliance with the License.
6+
* A copy of the License is located at
7+
*
8+
* http://aws.amazon.com/apache2.0
9+
*
10+
* or in the "license" file accompanying this file. This file is distributed
11+
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
12+
* express or implied. See the License for the specific language governing
13+
* permissions and limitations under the License.
14+
*/
15+
16+
package software.amazon.awssdk.auth.credentials.internal;
17+
18+
import software.amazon.awssdk.annotations.SdkInternalApi;
19+
import software.amazon.awssdk.auth.credentials.AwsCredentials;
20+
import software.amazon.awssdk.auth.signer.AwsSignerExecutionAttribute;
21+
import software.amazon.awssdk.core.SdkRequest;
22+
import software.amazon.awssdk.core.interceptor.Context;
23+
import software.amazon.awssdk.core.interceptor.ExecutionAttributes;
24+
import software.amazon.awssdk.core.interceptor.ExecutionInterceptor;
25+
import software.amazon.awssdk.core.interceptor.SdkInternalExecutionAttribute;
26+
import software.amazon.awssdk.core.useragent.BusinessMetricFeatureId;
27+
28+
/**
29+
* Interceptor that adds the CREDENTIALS_IMDS business metric when IMDS credentials are being used.
30+
*/
31+
@SdkInternalApi
32+
public final class ImdsCredentialsBusinessMetricInterceptor implements ExecutionInterceptor {
33+
34+
@Override
35+
public SdkRequest modifyRequest(Context.ModifyRequest context, ExecutionAttributes executionAttributes) {
36+
AwsCredentials credentials = executionAttributes.getAttribute(AwsSignerExecutionAttribute.AWS_CREDENTIALS);
37+
38+
if (credentials != null && isImdsCredentials(credentials)) {
39+
executionAttributes.getAttribute(SdkInternalExecutionAttribute.BUSINESS_METRICS)
40+
.addMetric(BusinessMetricFeatureId.CREDENTIALS_IMDS.value());
41+
}
42+
43+
return context.request();
44+
}
45+
46+
private boolean isImdsCredentials(AwsCredentials credentials) {
47+
return credentials.providerName()
48+
.map(name -> name.contains("InstanceProfile"))
49+
.orElse(false);
50+
}
51+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
software.amazon.awssdk.auth.credentials.internal.ImdsCredentialsBusinessMetricInterceptor
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
/*
2+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License").
5+
* You may not use this file except in compliance with the License.
6+
* A copy of the License is located at
7+
*
8+
* http://aws.amazon.com/apache2.0
9+
*
10+
* or in the "license" file accompanying this file. This file is distributed
11+
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
12+
* express or implied. See the License for the specific language governing
13+
* permissions and limitations under the License.
14+
*/
15+
16+
package software.amazon.awssdk.auth.credentials;
17+
18+
import static org.assertj.core.api.Assertions.assertThat;
19+
import static org.mockito.Mockito.mock;
20+
import static org.mockito.Mockito.when;
21+
22+
import java.util.Optional;
23+
import org.junit.jupiter.api.BeforeEach;
24+
import org.junit.jupiter.api.Test;
25+
import software.amazon.awssdk.auth.credentials.internal.ImdsCredentialsBusinessMetricInterceptor;
26+
import software.amazon.awssdk.auth.signer.AwsSignerExecutionAttribute;
27+
import software.amazon.awssdk.core.SdkRequest;
28+
import software.amazon.awssdk.core.interceptor.Context;
29+
import software.amazon.awssdk.core.interceptor.ExecutionAttributes;
30+
import software.amazon.awssdk.core.interceptor.SdkInternalExecutionAttribute;
31+
import software.amazon.awssdk.core.useragent.BusinessMetricCollection;
32+
import software.amazon.awssdk.core.useragent.BusinessMetricFeatureId;
33+
34+
public class ImdsCredentialsInUserAgentTest {
35+
36+
private ImdsCredentialsBusinessMetricInterceptor interceptor;
37+
private ExecutionAttributes executionAttributes;
38+
private BusinessMetricCollection businessMetrics;
39+
private Context.ModifyRequest context;
40+
41+
@BeforeEach
42+
void setUp() {
43+
interceptor = new ImdsCredentialsBusinessMetricInterceptor();
44+
executionAttributes = new ExecutionAttributes();
45+
businessMetrics = new BusinessMetricCollection();
46+
executionAttributes.putAttribute(SdkInternalExecutionAttribute.BUSINESS_METRICS, businessMetrics);
47+
48+
context = mock(Context.ModifyRequest.class);
49+
SdkRequest request = mock(SdkRequest.class);
50+
when(context.request()).thenReturn(request);
51+
}
52+
53+
@Test
54+
public void imdsCredentials_shouldHaveImdsCredentialsBusinessMetric() {
55+
// Create credentials with IMDS provider name
56+
AwsCredentials imdsCredentials = createCredentialsWithProviderName("InstanceProfileCredentialsProvider");
57+
executionAttributes.putAttribute(AwsSignerExecutionAttribute.AWS_CREDENTIALS, imdsCredentials);
58+
59+
interceptor.modifyRequest(context, executionAttributes);
60+
61+
assertThat(businessMetrics.recordedMetrics())
62+
.contains(BusinessMetricFeatureId.CREDENTIALS_IMDS.value());
63+
}
64+
65+
@Test
66+
public void regularCredentials_shouldNotHaveImdsCredentialsBusinessMetric() {
67+
// Create credentials with non-IMDS provider name
68+
AwsCredentials regularCredentials = createCredentialsWithProviderName("DefaultCredentialsProvider");
69+
executionAttributes.putAttribute(AwsSignerExecutionAttribute.AWS_CREDENTIALS, regularCredentials);
70+
71+
interceptor.modifyRequest(context, executionAttributes);
72+
73+
assertThat(businessMetrics.recordedMetrics())
74+
.doesNotContain(BusinessMetricFeatureId.CREDENTIALS_IMDS.value());
75+
}
76+
77+
@Test
78+
public void containerCredentials_shouldNotHaveImdsCredentialsBusinessMetric() {
79+
// Test with "ContainerCredentialsProvider" provider name - should NOT be considered IMDS
80+
AwsCredentials containerCredentials = createCredentialsWithProviderName("ContainerCredentialsProvider");
81+
executionAttributes.putAttribute(AwsSignerExecutionAttribute.AWS_CREDENTIALS, containerCredentials);
82+
83+
interceptor.modifyRequest(context, executionAttributes);
84+
85+
assertThat(businessMetrics.recordedMetrics())
86+
.doesNotContain(BusinessMetricFeatureId.CREDENTIALS_IMDS.value());
87+
}
88+
89+
@Test
90+
public void credentialsWithoutProviderName_shouldNotHaveImdsCredentialsBusinessMetric() {
91+
// Test with credentials that don't have a provider name
92+
AwsCredentials credentialsWithoutProviderName = AwsBasicCredentials.create("accessKey", "secretKey");
93+
executionAttributes.putAttribute(AwsSignerExecutionAttribute.AWS_CREDENTIALS, credentialsWithoutProviderName);
94+
95+
interceptor.modifyRequest(context, executionAttributes);
96+
97+
assertThat(businessMetrics.recordedMetrics())
98+
.doesNotContain(BusinessMetricFeatureId.CREDENTIALS_IMDS.value());
99+
}
100+
101+
private AwsCredentials createCredentialsWithProviderName(String providerName) {
102+
AwsCredentials baseCredentials = AwsBasicCredentials.create("accessKey", "secretKey");
103+
return new AwsCredentials() {
104+
@Override
105+
public String accessKeyId() {
106+
return baseCredentials.accessKeyId();
107+
}
108+
109+
@Override
110+
public String secretAccessKey() {
111+
return baseCredentials.secretAccessKey();
112+
}
113+
114+
@Override
115+
public Optional<String> providerName() {
116+
return Optional.of(providerName);
117+
}
118+
};
119+
}
120+
}

core/sdk-core/src/main/java/software/amazon/awssdk/core/useragent/BusinessMetricFeatureId.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
/**
2323
* An enum class representing a short form of identity providers to record in the UA string.
2424
*
25-
* Unimplemented metrics: I,J,K,M,O,S,U-c,e-[latest]
25+
* Unimplemented metrics: I,M,O,S,U-c,e-[latest]
2626
* Unsupported metrics (these will never be added): A,H
2727
*/
2828
@SdkProtectedApi
@@ -34,6 +34,8 @@ public enum BusinessMetricFeatureId {
3434
RETRY_MODE_STANDARD("E"),
3535
RETRY_MODE_ADAPTIVE("F"),
3636
S3_TRANSFER("G"),
37+
S3_EXPRESS_BUCKET("J"),
38+
S3_ACCESS_GRANTS("K"),
3739
GZIP_REQUEST_COMPRESSION("L"), //TODO(metrics): Not working, compression happens after header
3840
ENDPOINT_OVERRIDE("N"),
3941
ACCOUNT_ID_MODE_PREFERRED("P"),
@@ -42,6 +44,7 @@ public enum BusinessMetricFeatureId {
4244
RESOLVED_ACCOUNT_ID("T"),
4345
DDB_MAPPER("d"),
4446
BEARER_SERVICE_ENV_VARS("3"),
47+
CREDENTIALS_IMDS("0"),
4548
UNKNOWN("Unknown");
4649

4750
private static final Map<String, BusinessMetricFeatureId> VALUE_MAP =

0 commit comments

Comments
 (0)