Skip to content

Commit

Permalink
codegen: normalize adding of sigv4a config based on trait presence (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
lucix-aws authored Jan 24, 2024
1 parent 982db6d commit 7365edd
Show file tree
Hide file tree
Showing 13 changed files with 101 additions and 506 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ public List<RuntimeClientPlugin> getClientPlugins() {
// Add streaming events payload middleware to operation stack
RuntimeClientPlugin.builder()
.operationPredicate((model, service, operation) -> {
if (!AwsSignatureVersion4.hasSigV4AuthScheme(
if (!AwsSignatureVersion4.hasSigV4X(
model, service, operation)) {
return false;
}
Expand All @@ -79,7 +79,7 @@ public List<RuntimeClientPlugin> getClientPlugins() {
// Add unsigned payload middleware to operation stack
RuntimeClientPlugin.builder()
.operationPredicate((model, service, operation) -> {
if (!AwsSignatureVersion4.hasSigV4AuthScheme(
if (!AwsSignatureVersion4.hasSigV4X(
model, service, operation)) {
return false;
}
Expand All @@ -96,7 +96,7 @@ public List<RuntimeClientPlugin> getClientPlugins() {
// Add signed payload middleware to operation stack
RuntimeClientPlugin.builder()
.operationPredicate((model, service, operation) -> {
if (!AwsSignatureVersion4.hasSigV4AuthScheme(
if (!AwsSignatureVersion4.hasSigV4X(
model, service, operation)) {
return false;
}
Expand All @@ -113,7 +113,7 @@ public List<RuntimeClientPlugin> getClientPlugins() {
// Add content-sha256 payload header middleware to operation stack
RuntimeClientPlugin.builder()
.operationPredicate((model, service, operation) -> {
if (!AwsSignatureVersion4.hasSigV4AuthScheme(
if (!AwsSignatureVersion4.hasSigV4X(
model, service, operation)) {
return false;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@

import java.util.List;
import java.util.Map;

import software.amazon.smithy.aws.traits.auth.SigV4ATrait;
import software.amazon.smithy.aws.traits.auth.SigV4Trait;
import software.amazon.smithy.codegen.core.Symbol;
import software.amazon.smithy.codegen.core.SymbolProvider;
Expand Down Expand Up @@ -154,4 +156,10 @@ public static boolean hasSigV4AuthScheme(Model model, ServiceShape service, Oper
Map<ShapeId, Trait> auth = ServiceIndex.of(model).getEffectiveAuthSchemes(service.getId(), operation.getId());
return auth.containsKey(SigV4Trait.ID) && !operation.hasTrait(OptionalAuthTrait.class);
}

public static boolean hasSigV4X(Model model, ServiceShape service, OperationShape operation) {
var auth = ServiceIndex.of(model)
.getEffectiveAuthSchemes(service.getId(), operation.getId());
return auth.containsKey(SigV4Trait.ID) || auth.containsKey(SigV4ATrait.ID);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,56 +16,20 @@
package software.amazon.smithy.aws.go.codegen;

import software.amazon.smithy.aws.go.codegen.customization.AwsCustomGoDependency;
import software.amazon.smithy.go.codegen.GoDependency;
import software.amazon.smithy.go.codegen.GoWriter;
import software.amazon.smithy.go.codegen.SmithyGoDependency;
import software.amazon.smithy.go.codegen.SymbolUtils;
import software.amazon.smithy.model.Model;
import software.amazon.smithy.model.shapes.ServiceShape;

/**
* Generates Client Configuration, Middleware, and Config Resolvers for AWS Signature Version 4a support.
*/
public final class AwsSignatureVersion4aUtils {
public static final String RESOLVE_CREDENTIAL_PROVIDER = "resolveCredentialProvider";
public static final String REGISTER_MIDDLEWARE_FUNCTION = "swapWithCustomHTTPSignerMiddleware";
public static final String V4A_SIGNER_INTERFACE_NAME = "httpSignerV4a";
public static final String SIGNER_OPTION_FIELD_NAME = V4A_SIGNER_INTERFACE_NAME;
public static final String NEW_SIGNER_FUNC_NAME = "newDefaultV4aSigner";
public static final String SIGNER_RESOLVER = "resolveHTTPSignerV4a";

public static void writeCredentialProviderResolver(GoWriter writer) {
writer.pushState();
writer.putContext("resolverName", RESOLVE_CREDENTIAL_PROVIDER);
writer.putContext("fieldName", AddAwsConfigFields.CREDENTIALS_CONFIG_NAME);
writer.putContext("credType", SymbolUtils.createPointableSymbolBuilder("CredentialsProvider",
AwsCustomGoDependency.INTERNAL_SIGV4A).build());
writer.putContext("anonType", SymbolUtils.createPointableSymbolBuilder("AnonymousCredentials",
AwsCustomGoDependency.AWS_CORE).build());
writer.putContext("isProvider", SymbolUtils.createValueSymbolBuilder("IsCredentialsProvider",
AwsCustomGoDependency.AWS_CORE).build());
writer.putContext("adapType", SymbolUtils.createPointableSymbolBuilder("SymmetricCredentialAdaptor",
AwsCustomGoDependency.INTERNAL_SIGV4A).build());
writer.write("""
func $resolverName:L(o *Options) {
if o.$fieldName:L == nil {
return
}
if _, ok := o.$fieldName:L.($credType:T); ok {
return
}
if $isProvider:T(o.$fieldName:L, ($anonType:P)(nil)) {
return
}
o.$fieldName:L = &$adapType:T{SymmetricProvider: o.$fieldName:L}
}
""");
writer.popState();
}

public static void writerSignerInterface(GoWriter writer) {
writer.pushState();
writer.putContext("ifaceName", V4A_SIGNER_INTERFACE_NAME);
Expand Down Expand Up @@ -106,14 +70,6 @@ public static void writerConfigFieldResolver(GoWriter writer, ServiceShape servi
}

public static void writeNewV4ASignerFunc(GoWriter writer, ServiceShape serviceShape) {
writeNewV4ASignerFunc(writer, serviceShape, false);
}

public static void writeNewV4ASignerFunc(
GoWriter writer,
ServiceShape serviceShape,
boolean disableURIPathEscaping
) {
writer.pushState();
writer.putContext("funcName", NEW_SIGNER_FUNC_NAME);
writer.putContext("signerType", SymbolUtils.createPointableSymbolBuilder("Signer",
Expand All @@ -124,49 +80,12 @@ public static void writeNewV4ASignerFunc(
AwsCustomGoDependency.INTERNAL_SIGV4A).build());
writer.putContext("loggerField", AddAwsConfigFields.LOGGER_CONFIG_NAME);
writer.putContext("modeField", AddAwsConfigFields.LOG_MODE_CONFIG_NAME);
writer.putContext("disableEscape", disableURIPathEscaping);
writer.write("""
func $funcName:L(o Options) $signerType:P {
return $newSigner:T(func(so $signerOptions:P){
so.Logger = o.$loggerField:L
so.LogSigning = o.$modeField:L.IsSigning()
so.DisableURIPathEscaping = $disableEscape:L
})
}
""");
writer.popState();
}

public static void writeMiddlewareRegister(
Model model,
GoWriter writer,
ServiceShape serviceShape,
GoDependency signerMiddleware
) {
writer.pushState();
writer.putContext("funcName", REGISTER_MIDDLEWARE_FUNCTION);
writer.putContext("stackType", SymbolUtils.createPointableSymbolBuilder("Stack",
SmithyGoDependency.SMITHY_MIDDLEWARE).build());
writer.putContext("newMiddleware", SymbolUtils.createValueSymbolBuilder(
"NewSignHTTPRequestMiddleware", signerMiddleware).build());
writer.putContext("middleOptions", SymbolUtils.createValueSymbolBuilder(
"SignHTTPRequestMiddlewareOptions", signerMiddleware).build());
writer.putContext("registerMiddleware", SymbolUtils.createValueSymbolBuilder(
"RegisterSigningMiddleware", signerMiddleware).build());
writer.putContext("credFileName", AddAwsConfigFields.CREDENTIALS_CONFIG_NAME);
writer.putContext("v4Signer", AwsSignatureVersion4.SIGNER_CONFIG_FIELD_NAME);
writer.putContext("v4aSigner", SIGNER_OPTION_FIELD_NAME);
writer.putContext("logMode", AddAwsConfigFields.LOG_MODE_CONFIG_NAME);
writer.write("""
func $funcName:L(stack $stackType:P, o Options) error {
mw := $newMiddleware:T($middleOptions:T{
CredentialsProvider: o.$credFileName:L,
V4Signer: o.$v4Signer:L,
V4aSigner: o.$v4aSigner:L,
LogSigning: o.$logMode:L.IsSigning(),
})
return $registerMiddleware:T(stack, mw)
}
""");
writer.popState();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,36 +1,39 @@
/*
* Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://aws.amazon.com/apache2.0
*
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*
*
*/

package software.amazon.smithy.aws.go.codegen.customization;

import java.util.List;
import java.util.ArrayList;
import software.amazon.smithy.aws.go.codegen.AddAwsConfigFields;
import software.amazon.smithy.aws.go.codegen.AwsGoDependency;
import software.amazon.smithy.aws.go.codegen.AwsSignatureVersion4;
import software.amazon.smithy.aws.go.codegen.AwsSignatureVersion4aUtils;
import software.amazon.smithy.aws.traits.ServiceTrait;
import software.amazon.smithy.aws.traits.auth.SigV4ATrait;
import software.amazon.smithy.aws.traits.auth.SigV4Trait;
import software.amazon.smithy.codegen.core.Symbol;
import software.amazon.smithy.codegen.core.SymbolProvider;
import software.amazon.smithy.go.codegen.GoDelegator;
import software.amazon.smithy.go.codegen.GoSettings;
import software.amazon.smithy.go.codegen.GoWriter;
import software.amazon.smithy.go.codegen.SmithyGoDependency;
import software.amazon.smithy.go.codegen.SymbolUtils;
import software.amazon.smithy.go.codegen.integration.ConfigField;
import software.amazon.smithy.go.codegen.integration.ConfigFieldResolver;
import software.amazon.smithy.go.codegen.integration.GoIntegration;
import software.amazon.smithy.go.codegen.integration.MiddlewareRegistrar;
import software.amazon.smithy.go.codegen.integration.RuntimeClientPlugin;
import software.amazon.smithy.model.Model;
import software.amazon.smithy.model.shapes.ServiceShape;
import software.amazon.smithy.model.traits.AuthTrait;
import software.amazon.smithy.utils.ListUtils;
import software.amazon.smithy.utils.SetUtils;

/**
* This integration configures the CloudFront Key Value Store client for Signature Version 4a
*/
public class CloudFrontKVSSigV4a implements GoIntegration {
// hardcoded from model so we don't have to extract it from whatever auth trait
private static final String SIGNING_NAME = "cloudfront-keyvaluestore";

/**
* Return true if service is CFKVS.
*
Expand All @@ -43,106 +46,23 @@ private static boolean isCFKVSService(Model model, ServiceShape service) {
return serviceId.equalsIgnoreCase("cloudfrontkeyvaluestore");
}

private final List<RuntimeClientPlugin> runtimeClientPlugins = new ArrayList<>();


@Override
public List<RuntimeClientPlugin> getClientPlugins() {
return runtimeClientPlugins;
}

@Override
public Model preprocessModel(Model model, GoSettings settings) {
ServiceShape service = settings.getService(model);
if (!isCFKVSService(model, service)) {
return model;
}

if (settings.getService(model).hasTrait(SigV4ATrait.class)) {
return model;
}

var v4a = SigV4ATrait.builder()
.name(service.expectTrait(SigV4Trait.class).getName())
.build();

// we MUST preserve the sigv4 trait as released since it affects the exported API
// (signer interface and config field)
return model.toBuilder()
.addShape(
service.toBuilder()
.addTrait(v4a)
// FUTURE: https://github.com/aws/smithy-go/issues/493
// we are keeping sigv4 at the end of this list (it will never be selected)
// as a stopgap to drive codegen of payload checksum routines
.addTrait(SigV4ATrait.builder().name(SIGNING_NAME).build())
.addTrait(SigV4Trait.builder().name(SIGNING_NAME).build())
.addTrait(new AuthTrait(SetUtils.of(SigV4ATrait.ID, SigV4Trait.ID)))
.build()
)
.build();
}

@Override
public void processFinalizedModel(GoSettings settings, Model model) {
if (!isCFKVSService(model, settings.getService(model))) {
return;
}
runtimeClientPlugins.add(
RuntimeClientPlugin.builder()
.configFields(
ListUtils.of(
ConfigField.builder()
.name(AwsSignatureVersion4aUtils.V4A_SIGNER_INTERFACE_NAME)
.type(SymbolUtils.buildPackageSymbol(
AwsSignatureVersion4aUtils.V4A_SIGNER_INTERFACE_NAME)
)
.documentation("Signature Version 4a (SigV4a) Signer")
.build()
)
)
.build());
runtimeClientPlugins.add(
RuntimeClientPlugin.builder()
.servicePredicate(CloudFrontKVSSigV4a::isCFKVSService)
.addConfigFieldResolver(
ConfigFieldResolver.builder()
.location(ConfigFieldResolver.Location.CLIENT)
.target(ConfigFieldResolver.Target.INITIALIZATION)
.resolver(SymbolUtils.createValueSymbolBuilder(
AwsSignatureVersion4aUtils.SIGNER_RESOLVER).build())
.build())
.build());
}

@Override
public void writeAdditionalFiles(
GoSettings settings,
Model model,
SymbolProvider symbolProvider,
GoDelegator goDelegator
) {

if (!isCFKVSService(model, model.expectShape(settings.getService(), ServiceShape.class))) {
return;
}

ServiceShape serviceShape = settings.getService(model);
goDelegator.useShapeWriter(serviceShape, writer -> {
writerSignerInterface(writer);
writerConfigFieldResolver(writer, serviceShape);
writeNewV4ASignerFunc(writer, serviceShape);
});

}


private void writerSignerInterface(GoWriter writer) {
AwsSignatureVersion4aUtils.writerSignerInterface(writer);
}

private void writeNewV4ASignerFunc(GoWriter writer, ServiceShape serviceShape) {
AwsSignatureVersion4aUtils.writeNewV4ASignerFunc(writer, serviceShape);
}

private void writerConfigFieldResolver(GoWriter writer, ServiceShape serviceShape) {
AwsSignatureVersion4aUtils.writerConfigFieldResolver(writer, serviceShape);
}

}
Loading

0 comments on commit 7365edd

Please sign in to comment.