Skip to content

Commit 36c89a0

Browse files
authored
Multi-Auth Sigv4a Support (#5868)
* Add support for Multi Auth Sigv4a for Service metadata (#5761) * Add support for Multi Auth Sigv4a for Service metadata * handled comments * Sigv4aSigningRegionSetProvider and updating Execution Attributes (#5762) * Sigv4aSigningRegionSetProvider and updating Execution Attributes * Fixed typos * Handled comments * extra space * Handled comments * Handled comments to make RegionSet Provider as Internal API * Update AuthScemeParams with RegionSet for Sigv4a auth Scheme (#5766) * Codegen changes for AuthSchemeInterceptorSpecs to update the RegionSet from Execution Attributes (#5768) * Update AuthScemeParams with RegionSet for Sigv4a auth Scheme * Update Codegen AuthSchemeInterceptorSpec to update RegionSet for AuthSchemeParams * updated method name * Add sigv4aRegionSet to Client Builder for Multi-Auth Services Supporting Sigv4a (#5772) * Update AuthScemeParams with RegionSet for Sigv4a auth Scheme * Update Codegen AuthSchemeInterceptorSpec to update RegionSet for AuthSchemeParams * updated method name * Adding sigv4aResionSet client builder for services which has Sigv4a in Multi Auth trait * Adding Codegen support for unsignedPayload model trait for multi-auth auth schemes (#5776) * Update AuthScemeParams with RegionSet for Sigv4a auth Scheme * Update Codegen AuthSchemeInterceptorSpec to update RegionSet for AuthSchemeParams * updated method name * Adding sigv4aResionSet client builder for services which has Sigv4a in Multi Auth trait * Adding Codegen support for unsignedPayload model trait for multi-auth auth schemes * Adding Codegen support for unsignedPayload model trait for multi-auth auth schemes * Adding Codegen support for unsignedPayload model trait for multi-auth auth schemes * Handled comments * updated variable names * Remove `useMultiAuth` customization (#5800) * Remove multiAuth customization * Handle cases where AuthType gets updated from Legacy signature version * Override RegionSet in EnpointResolverInterceptor after fetching the Signing Properties from Endpoint rules (#5825) * Override RegionSet in EnpointResolverInterceptor after fetching the Signing Properties from Endpoint rules * Endpoint Resolver Spec test added * Add test case for service with MultiAuth only and not using Sigv4 * checkstyle fixed * Handled comments * Updated after Integ test failure and some comments * Resolve Sigv4a regionset from Client configs if Endpoint-Based-Auth legacy modules doesnot have it defined in ruleset (#5860) * Override RegionSet in EnpointResolverInterceptor after fetching the Signing Properties from Endpoint rules * Endpoint Resolver Spec test added * Add test case for service with MultiAuth only and not using Sigv4 * checkstyle fixed * Handled comments * Updated after Integ test failure and some comments * Sigv4a Regionset updated for Endpoint-based-Auth Legacy services * Added endpoint-resolve-interceptor-with-endpointsbasedauth.java * Added test cases to check runtime resolution of RegionSet * Updated test cases to make sure we check Empty set * fixed test build * Changed precedence after internal discussion * Renamed API name `sigv4aRegionSet` to `sigv4aSigningRegionSet` to be conssistent with Environment variable and System Property name for this option (#5867) * Changed API names sigv4aRegionSet to sigv4aSigningRegionSet to be consistent with Environmant variable and System Property name for this option * Fixed checkstyle issues * Added S3 junit with wiremock tests for Mult Auth Sigv4a (#5872)
1 parent 15fe972 commit 36c89a0

File tree

78 files changed

+4558
-106
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

78 files changed

+4558
-106
lines changed

codegen/src/main/java/software/amazon/awssdk/codegen/AddMetadata.java

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -74,13 +74,14 @@ public static Metadata constructMetadata(ServiceModel serviceModel,
7474
.withJsonVersion(serviceMetadata.getJsonVersion())
7575
.withEndpointPrefix(serviceMetadata.getEndpointPrefix())
7676
.withSigningName(serviceMetadata.getSigningName())
77-
.withAuthType(AuthType.fromValue(serviceMetadata.getSignatureVersion()))
77+
.withAuthType(serviceMetadata.getSignatureVersion() != null ?
78+
AuthType.fromValue(serviceMetadata.getSignatureVersion()) : null)
7879
.withUid(serviceMetadata.getUid())
7980
.withServiceId(serviceMetadata.getServiceId())
8081
.withSupportsH2(supportsH2(serviceMetadata))
8182
.withJsonVersion(getJsonVersion(metadata, serviceMetadata))
8283
.withAwsQueryCompatible(serviceMetadata.getAwsQueryCompatible())
83-
.withAuth(getAuthFromServiceMetadata(serviceMetadata, customizationConfig.useMultiAuth()));
84+
.withAuth(getAuthFromServiceMetadata(serviceMetadata));
8485

8586
return metadata;
8687
}
@@ -136,18 +137,14 @@ private static String getJsonVersion(Metadata metadata, ServiceMetadata serviceM
136137
}
137138

138139
/**
139-
* Converts service metadata into a list of AuthTypes. If useMultiAuth is enabled, then
140-
* {@code metadata.auth} will be used in the conversion if present. Otherwise, use
141-
* {@code metadata.signatureVersion}.
140+
* Converts a list of authentication type strings from the given {@link ServiceMetadata} into a list of
141+
* {@link AuthType} objects.
142142
*/
143-
private static List<AuthType> getAuthFromServiceMetadata(ServiceMetadata serviceMetadata,
144-
boolean useMultiAuth) {
145-
if (useMultiAuth) {
146-
List<String> serviceAuth = serviceMetadata.getAuth();
147-
if (serviceAuth != null) {
148-
return serviceAuth.stream().map(AuthType::fromValue).collect(Collectors.toList());
149-
}
143+
private static List<AuthType> getAuthFromServiceMetadata(ServiceMetadata serviceMetadata) {
144+
List<String> serviceAuth = serviceMetadata.getAuth();
145+
if (serviceAuth != null) {
146+
return serviceAuth.stream().map(AuthType::fromValue).collect(Collectors.toList());
150147
}
151-
return Collections.singletonList(AuthType.fromValue(serviceMetadata.getSignatureVersion()));
148+
return Collections.emptyList();
152149
}
153150
}

codegen/src/main/java/software/amazon/awssdk/codegen/AddOperations.java

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -47,14 +47,12 @@ final class AddOperations {
4747
private final NamingStrategy namingStrategy;
4848
private final Map<String, PaginatorDefinition> paginators;
4949
private final List<String> deprecatedShapes;
50-
private final boolean useMultiAuth;
5150

5251
AddOperations(IntermediateModelBuilder builder) {
5352
this.serviceModel = builder.getService();
5453
this.namingStrategy = builder.getNamingStrategy();
5554
this.paginators = builder.getPaginators().getPagination();
5655
this.deprecatedShapes = builder.getCustomConfig().getDeprecatedShapes();
57-
this.useMultiAuth = builder.getCustomConfig().useMultiAuth();
5856
}
5957

6058
private static boolean isAuthenticated(Operation op) {
@@ -182,6 +180,7 @@ public Map<String, OperationModel> constructOperations() {
182180
operationModel.setStaticContextParams(op.getStaticContextParams());
183181
operationModel.setOperationContextParams(op.getOperationContextParams());
184182
operationModel.setAuth(getAuthFromOperation(op));
183+
operationModel.setUnsignedPayload(op.isUnsignedPayload());
185184

186185
Input input = op.getInput();
187186
if (input != null) {
@@ -237,21 +236,23 @@ public Map<String, OperationModel> constructOperations() {
237236
}
238237

239238
/**
240-
* Returns the list of authTypes defined for an operation. If useMultiAuth is enabled, then
241-
* {@code operation.auth} will be used in the conversion if present. Otherwise, use
242-
* {@code operation.authtype} if present.
239+
* Retrieves the list of {@link AuthType} for the given operation.
240+
* <p>
241+
* If {@link Operation#getAuth()}is available, it is converted to a list of {@link AuthType}.
242+
* Otherwise, {@link Operation#getAuthtype()} is returned as a single-element list if present.
243+
* If neither is available, an empty list is returned.
243244
*/
244245
private List<AuthType> getAuthFromOperation(Operation op) {
245-
if (useMultiAuth) {
246-
List<String> opAuth = op.getAuth();
247-
if (opAuth != null) {
248-
return opAuth.stream().map(AuthType::fromValue).collect(Collectors.toList());
249-
}
250-
}
246+
247+
// First we check for legacy AuthType to support backward compatibility
251248
AuthType legacyAuthType = op.getAuthtype();
252249
if (legacyAuthType != null) {
253250
return Collections.singletonList(legacyAuthType);
254251
}
252+
List<String> opAuth = op.getAuth();
253+
if (opAuth != null) {
254+
return opAuth.stream().map(AuthType::fromValue).collect(Collectors.toList());
255+
}
255256
return Collections.emptyList();
256257
}
257258

codegen/src/main/java/software/amazon/awssdk/codegen/model/config/customization/CustomizationConfig.java

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -324,13 +324,6 @@ public class CustomizationConfig {
324324
*/
325325
private String rootPackageName;
326326

327-
/**
328-
* Set to true to read from c2j multi-auth values. Currently defaults to false.
329-
*
330-
* TODO(multi-auth): full multi-auth support is not implemented
331-
*/
332-
private boolean useMultiAuth;
333-
334327
/**
335328
* Special case for a service where model changes for endpoint params were not updated .
336329
* This should be removed once the service updates its models
@@ -891,14 +884,6 @@ public CustomizationConfig withRootPackageName(String packageName) {
891884
return this;
892885
}
893886

894-
public void setUseMultiAuth(boolean useMultiAuth) {
895-
this.useMultiAuth = useMultiAuth;
896-
}
897-
898-
public boolean useMultiAuth() {
899-
return useMultiAuth;
900-
}
901-
902887
public Map<String, ParameterModel> getEndpointParameters() {
903888
return endpointParameters;
904889
}

codegen/src/main/java/software/amazon/awssdk/codegen/model/intermediate/OperationModel.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,8 @@ public class OperationModel extends DocumentationModel {
8787
@JsonIgnore
8888
private Map<String, OperationContextParam> operationContextParams;
8989

90+
private boolean unsignedPayload;
91+
9092
public String getOperationName() {
9193
return operationName;
9294
}
@@ -369,4 +371,12 @@ public Map<String, OperationContextParam> getOperationContextParams() {
369371
public void setOperationContextParams(Map<String, OperationContextParam> operationContextParams) {
370372
this.operationContextParams = operationContextParams;
371373
}
374+
375+
public boolean isUnsignedPayload() {
376+
return unsignedPayload;
377+
}
378+
379+
public void setUnsignedPayload(boolean unsignedPayload) {
380+
this.unsignedPayload = unsignedPayload;
381+
}
372382
}

codegen/src/main/java/software/amazon/awssdk/codegen/model/service/AuthType.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ public enum AuthType {
2424
CUSTOM("custom"),
2525
IAM("iam"),
2626
V4("v4"),
27+
V4A("v4a"),
2728
V4_UNSIGNED_BODY("v4-unsigned-body"),
2829
S3("s3"),
2930
S3V4("s3v4"),
@@ -49,6 +50,8 @@ public static AuthType fromValue(String value) {
4950
return NONE;
5051
case "aws.auth#sigv4":
5152
return V4;
53+
case "aws.auth#sigv4a":
54+
return V4A;
5255
default:
5356
String normalizedValue = StringUtils.lowerCase(value);
5457
return Arrays.stream(values())

codegen/src/main/java/software/amazon/awssdk/codegen/model/service/Operation.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,8 @@ public class Operation {
6161

6262
private Map<String, OperationContextParam> operationContextParams;
6363

64+
private boolean unsignedPayload;
65+
6466
public String getName() {
6567
return name;
6668
}
@@ -227,4 +229,12 @@ public Map<String, OperationContextParam> getOperationContextParams() {
227229
public void setOperationContextParams(Map<String, OperationContextParam> operationContextParams) {
228230
this.operationContextParams = operationContextParams;
229231
}
232+
233+
public boolean isUnsignedPayload() {
234+
return unsignedPayload;
235+
}
236+
237+
public void setUnsignedPayload(boolean unsignedPayload) {
238+
this.unsignedPayload = unsignedPayload;
239+
}
230240
}

codegen/src/main/java/software/amazon/awssdk/codegen/poet/auth/scheme/AuthSchemeCodegenMetadataExt.java

Lines changed: 76 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,10 @@
2525
import software.amazon.awssdk.codegen.model.service.AuthType;
2626
import software.amazon.awssdk.codegen.poet.auth.scheme.AuthSchemeCodegenMetadata.SignerPropertyValueProvider;
2727
import software.amazon.awssdk.http.auth.aws.scheme.AwsV4AuthScheme;
28+
import software.amazon.awssdk.http.auth.aws.scheme.AwsV4aAuthScheme;
29+
import software.amazon.awssdk.http.auth.aws.signer.AwsV4FamilyHttpSigner;
2830
import software.amazon.awssdk.http.auth.aws.signer.AwsV4HttpSigner;
31+
import software.amazon.awssdk.http.auth.aws.signer.AwsV4aHttpSigner;
2932
import software.amazon.awssdk.http.auth.scheme.BearerAuthScheme;
3033
import software.amazon.awssdk.http.auth.scheme.NoAuthAuthScheme;
3134
import software.amazon.awssdk.http.auth.spi.scheme.AuthSchemeOption;
@@ -59,6 +62,24 @@ public final class AuthSchemeCodegenMetadataExt {
5962
.authSchemeClass(BearerAuthScheme.class)
6063
.build();
6164

65+
static final AuthSchemeCodegenMetadata SIGV4A =
66+
builder()
67+
.schemeId(AwsV4aAuthScheme.SCHEME_ID)
68+
.authSchemeClass(AwsV4aAuthScheme.class)
69+
.addProperty(SignerPropertyValueProvider.builder()
70+
.containingClass(AwsV4aHttpSigner.class)
71+
.fieldName(
72+
"SERVICE_SIGNING_NAME")
73+
.valueEmitter((spec, utils) -> spec.add("$S", utils.signingName()))
74+
.build())
75+
.addProperty(SignerPropertyValueProvider.builder()
76+
.containingClass(AwsV4aHttpSigner.class)
77+
.fieldName(
78+
"REGION_SET")
79+
.valueEmitter((spec, utils) -> spec.add("$L", "params.regionSet()"))
80+
.build())
81+
.build();
82+
6283
static final AuthSchemeCodegenMetadata NO_AUTH = builder()
6384
.schemeId(NoAuthAuthScheme.SCHEME_ID)
6485
.authSchemeClass(NoAuthAuthScheme.class)
@@ -71,20 +92,32 @@ private AuthSchemeCodegenMetadataExt() {
7192
/**
7293
* Creates a new auth scheme codegen metadata instance using the defaults for the given {@link AuthType} defaults.
7394
*/
74-
public static AuthSchemeCodegenMetadata fromAuthType(AuthType type) {
75-
switch (type) {
95+
public static AuthSchemeCodegenMetadata fromAuthType(AuthTrait authTrait) {
96+
switch (authTrait.authType()) {
7697
case BEARER:
7798
return BEARER;
7899
case NONE:
79100
return NO_AUTH;
101+
case V4A:
102+
return getSigv4aAuthSchemeBuilder(authTrait).build();
80103
default:
81-
String authTypeName = type.value();
82-
SigV4SignerDefaults defaults = AuthTypeToSigV4Default.authTypeToDefaults().get(authTypeName);
83-
if (defaults == null) {
84-
throw new IllegalArgumentException("Unknown auth type: " + type);
85-
}
86-
return fromConstants(defaults);
104+
return resolveAuthSchemeForType(authTrait);
105+
}
106+
}
107+
108+
private static AuthSchemeCodegenMetadata resolveAuthSchemeForType(AuthTrait authTrait) {
109+
String authTypeName = authTrait.authType().value();
110+
SigV4SignerDefaults defaults = AuthTypeToSigV4Default.authTypeToDefaults().get(authTypeName);
111+
112+
if (defaults == null) {
113+
throw new IllegalArgumentException("Unknown auth option: " + authTrait + " with type " + authTypeName);
87114
}
115+
if (authTrait.isUnsignedPayload()) {
116+
defaults = defaults.toBuilder()
117+
.payloadSigningEnabled(false)
118+
.build();
119+
}
120+
return fromConstants(defaults);
88121
}
89122

90123
/**
@@ -149,25 +182,54 @@ public static CodeBlock codegenSignerPropertiesIfAbsent(
149182
private static List<SignerPropertyValueProvider> propertiesFromConstants(SigV4SignerDefaults constants) {
150183
List<SignerPropertyValueProvider> properties = new ArrayList<>();
151184
if (constants.payloadSigningEnabled() != null) {
152-
properties.add(from("PAYLOAD_SIGNING_ENABLED", constants::payloadSigningEnabled));
185+
properties.add(from("PAYLOAD_SIGNING_ENABLED", constants::payloadSigningEnabled, AwsV4HttpSigner.class));
153186
}
154187
if (constants.doubleUrlEncode() != null) {
155-
properties.add(from("DOUBLE_URL_ENCODE", constants::doubleUrlEncode));
188+
properties.add(from("DOUBLE_URL_ENCODE", constants::doubleUrlEncode, AwsV4HttpSigner.class));
156189
}
157190
if (constants.normalizePath() != null) {
158-
properties.add(from("NORMALIZE_PATH", constants::normalizePath));
191+
properties.add(from("NORMALIZE_PATH", constants::normalizePath, AwsV4HttpSigner.class));
159192
}
160193
if (constants.chunkEncodingEnabled() != null) {
161-
properties.add(from("CHUNK_ENCODING_ENABLED", constants::chunkEncodingEnabled));
194+
properties.add(from("CHUNK_ENCODING_ENABLED", constants::chunkEncodingEnabled, AwsV4HttpSigner.class));
162195
}
163196
return properties;
164197
}
165198

166-
private static SignerPropertyValueProvider from(String name, Supplier<Object> valueSupplier) {
199+
private static SignerPropertyValueProvider from(String name,
200+
Supplier<Object> valueSupplier,
201+
Class<? extends AwsV4FamilyHttpSigner> containingClass) {
167202
return SignerPropertyValueProvider.builder()
168-
.containingClass(AwsV4HttpSigner.class)
203+
.containingClass(containingClass)
169204
.fieldName(name)
170205
.constantValueSupplier(valueSupplier)
171206
.build();
172207
}
208+
209+
private static Builder getSigv4aAuthSchemeBuilder(AuthTrait authTrait) {
210+
Builder sigv4aBuilder = builder()
211+
.schemeId(AwsV4aAuthScheme.SCHEME_ID)
212+
.authSchemeClass(AwsV4aAuthScheme.class);
213+
214+
addCommonSigv4aProperties(sigv4aBuilder);
215+
216+
if (authTrait.isUnsignedPayload()) {
217+
sigv4aBuilder.addProperty(from("PAYLOAD_SIGNING_ENABLED", () -> false, AwsV4aHttpSigner.class));
218+
}
219+
return sigv4aBuilder;
220+
}
221+
222+
private static void addCommonSigv4aProperties(Builder builder) {
223+
builder.addProperty(SignerPropertyValueProvider.builder()
224+
.containingClass(AwsV4aHttpSigner.class)
225+
.fieldName("SERVICE_SIGNING_NAME")
226+
.valueEmitter((spec, utils) -> spec.add("$S", utils.signingName()))
227+
.build())
228+
.addProperty(SignerPropertyValueProvider.builder()
229+
.containingClass(AwsV4aHttpSigner.class)
230+
.fieldName("REGION_SET")
231+
.valueEmitter((spec, utils) -> spec.add("$L", "params.regionSet()"))
232+
.build());
233+
}
234+
173235
}

codegen/src/main/java/software/amazon/awssdk/codegen/poet/auth/scheme/AuthSchemeInterceptorSpec.java

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@
5050
import software.amazon.awssdk.core.internal.util.MetricUtils;
5151
import software.amazon.awssdk.core.metrics.CoreMetric;
5252
import software.amazon.awssdk.endpoints.EndpointProvider;
53+
import software.amazon.awssdk.http.auth.aws.signer.RegionSet;
5354
import software.amazon.awssdk.http.auth.spi.scheme.AuthScheme;
5455
import software.amazon.awssdk.http.auth.spi.scheme.AuthSchemeOption;
5556
import software.amazon.awssdk.http.auth.spi.signer.HttpSigner;
@@ -62,6 +63,7 @@
6263
import software.amazon.awssdk.metrics.MetricCollector;
6364
import software.amazon.awssdk.metrics.SdkMetric;
6465
import software.amazon.awssdk.regions.Region;
66+
import software.amazon.awssdk.utils.CollectionUtils;
6567
import software.amazon.awssdk.utils.Logger;
6668
import software.amazon.awssdk.utils.Validate;
6769

@@ -148,20 +150,17 @@ private MethodSpec generateAuthSchemeParams() {
148150
if (!authSchemeSpecUtils.useEndpointBasedAuthProvider()) {
149151
builder.addStatement("$T operation = executionAttributes.getAttribute($T.OPERATION_NAME)", String.class,
150152
SdkExecutionAttribute.class);
153+
builder.addStatement("$T.Builder builder = $T.builder().operation(operation)",
154+
authSchemeSpecUtils.parametersInterfaceName(),
155+
authSchemeSpecUtils.parametersInterfaceName());
156+
151157
if (authSchemeSpecUtils.usesSigV4()) {
152158
builder.addStatement("$T region = executionAttributes.getAttribute($T.AWS_REGION)", Region.class,
153159
AwsExecutionAttribute.class);
154-
builder.addStatement("return $T.builder()"
155-
+ ".operation(operation)"
156-
+ ".region(region)"
157-
+ ".build()",
158-
authSchemeSpecUtils.parametersInterfaceName());
159-
} else {
160-
builder.addStatement("return $T.builder()"
161-
+ ".operation(operation)"
162-
+ ".build()",
163-
authSchemeSpecUtils.parametersInterfaceName());
160+
builder.addStatement("builder.region(region)");
164161
}
162+
generateSigv4aSigningRegionSet(builder);
163+
builder.addStatement("return builder.build()");
165164
return builder.build();
166165
}
167166

@@ -187,6 +186,7 @@ private MethodSpec generateAuthSchemeParams() {
187186
AwsExecutionAttribute.class);
188187
builder.addStatement("builder.region(region)");
189188
}
189+
generateSigv4aSigningRegionSet(builder);
190190
ClassName paramsBuilderClass = authSchemeSpecUtils.parametersEndpointAwareDefaultImplName().nestedClass("Builder");
191191
builder.beginControlFlow("if (builder instanceof $T)",
192192
paramsBuilderClass);
@@ -449,4 +449,17 @@ private TypeName toTypeName(Object valueType) {
449449
}
450450
return result;
451451
}
452+
453+
private void generateSigv4aSigningRegionSet(MethodSpec.Builder builder) {
454+
if (authSchemeSpecUtils.hasSigV4aSupport()) {
455+
builder.addStatement(
456+
"executionAttributes.getOptionalAttribute($T.AWS_SIGV4A_SIGNING_REGION_SET)\n" +
457+
" .filter(regionSet -> !$T.isNullOrEmpty(regionSet))\n" +
458+
" .ifPresent(nonEmptyRegionSet -> builder.regionSet($T.create(nonEmptyRegionSet)))",
459+
AwsExecutionAttribute.class,
460+
CollectionUtils.class,
461+
RegionSet.class
462+
);
463+
}
464+
}
452465
}

0 commit comments

Comments
 (0)