From da4b2b6c951a94a0aabf576d6a30ac8d883e45d9 Mon Sep 17 00:00:00 2001 From: Luc Talatinian <102624213+lucix-aws@users.noreply.github.com> Date: Wed, 4 Oct 2023 11:14:35 -0700 Subject: [PATCH] add modeled endpoint resolver generation (#456) --- auth/auth.go | 3 + auth/identity.go | 26 +++ auth/option.go | 10 + codegen/smithy-go-codegen/build.gradle.kts | 1 + .../amazon/smithy/go/codegen/GoWriter.java | 4 + .../smithy/go/codegen/SmithyGoDependency.java | 1 + .../smithy/go/codegen/SmithyGoTypes.java | 16 ++ .../smithy/go/codegen/auth/AuthGenerator.java | 9 +- .../auth/AuthSchemeResolverGenerator.java | 202 ++++++++++++++++++ .../EndpointParameterBindingsGenerator.java | 10 +- .../integration/AuthSchemeDefinition.java | 38 ++++ .../integration/RuntimeClientPlugin.java | 23 ++ .../integration/auth/AnonymousAuthScheme.java | 36 ++++ .../integration/auth/AnonymousDefinition.java | 40 ++++ .../integration/auth/HttpBearerAuth.java | 6 + .../auth/HttpBearerDefinition.java | 40 ++++ .../SigV4AuthScheme.java} | 19 +- .../integration/auth/SigV4Definition.java | 70 ++++++ ...mithy.go.codegen.integration.GoIntegration | 7 +- properties.go | 12 +- transport/http/auth.go | 22 ++ transport/http/auth_options.go | 84 ++++++++ transport/http/auth_schemes.go | 84 ++++++++ transport/http/properties.go | 68 ++++++ 24 files changed, 813 insertions(+), 18 deletions(-) create mode 100644 auth/auth.go create mode 100644 auth/identity.go create mode 100644 auth/option.go create mode 100644 codegen/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/auth/AuthSchemeResolverGenerator.java create mode 100644 codegen/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/integration/AuthSchemeDefinition.java create mode 100644 codegen/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/integration/auth/AnonymousAuthScheme.java create mode 100644 codegen/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/integration/auth/AnonymousDefinition.java create mode 100644 codegen/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/integration/auth/HttpBearerDefinition.java rename codegen/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/integration/{SigV4AuthParameters.java => auth/SigV4AuthScheme.java} (55%) create mode 100644 codegen/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/integration/auth/SigV4Definition.java create mode 100644 transport/http/auth.go create mode 100644 transport/http/auth_options.go create mode 100644 transport/http/auth_schemes.go create mode 100644 transport/http/properties.go diff --git a/auth/auth.go b/auth/auth.go new file mode 100644 index 000000000..5bdb70c9a --- /dev/null +++ b/auth/auth.go @@ -0,0 +1,3 @@ +// Package auth defines protocol-agnostic authentication types for smithy +// clients. +package auth diff --git a/auth/identity.go b/auth/identity.go new file mode 100644 index 000000000..b8d8b4a71 --- /dev/null +++ b/auth/identity.go @@ -0,0 +1,26 @@ +package auth + +import ( + "context" + "time" + + "github.com/aws/smithy-go" +) + +// Identity contains information that identifies who the user making the +// request is. +type Identity interface { + Expiration() time.Time +} + +// IdentityResolver defines the interface through which an Identity is +// retrieved. +type IdentityResolver interface { + GetIdentity(ctx context.Context, params *smithy.Properties) (Identity, error) +} + +// IdentityResolverOptions defines the interface through which an entity can be +// queried to retrieve an IdentityResolver for a given auth scheme. +type IdentityResolverOptions interface { + GetIdentityResolver(schemeID string) IdentityResolver +} diff --git a/auth/option.go b/auth/option.go new file mode 100644 index 000000000..bf442554e --- /dev/null +++ b/auth/option.go @@ -0,0 +1,10 @@ +package auth + +import "github.com/aws/smithy-go" + +// Option represents a possible authentication method for an operation. +type Option struct { + SchemeID string + IdentityProperties smithy.Properties + SignerProperties smithy.Properties +} diff --git a/codegen/smithy-go-codegen/build.gradle.kts b/codegen/smithy-go-codegen/build.gradle.kts index 8ff377a42..c8e49f11b 100644 --- a/codegen/smithy-go-codegen/build.gradle.kts +++ b/codegen/smithy-go-codegen/build.gradle.kts @@ -21,6 +21,7 @@ extra["moduleName"] = "software.amazon.smithy.go.codegen" dependencies { api("software.amazon.smithy:smithy-codegen-core:$smithyVersion") + api("software.amazon.smithy:smithy-aws-traits:$smithyVersion") implementation("software.amazon.smithy:smithy-waiters:$smithyVersion") api("com.atlassian.commonmark:commonmark:0.15.2") api("org.jsoup:jsoup:1.14.1") diff --git a/codegen/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/GoWriter.java b/codegen/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/GoWriter.java index 0ac874a8f..4b91ccf54 100644 --- a/codegen/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/GoWriter.java +++ b/codegen/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/GoWriter.java @@ -998,6 +998,10 @@ public ChainWritable() { writables = new ArrayList<>(); } + public boolean isEmpty() { + return writables.isEmpty(); + } + public ChainWritable add(GoWriter.Writable writable) { writables.add(writable); return this; diff --git a/codegen/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/SmithyGoDependency.java b/codegen/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/SmithyGoDependency.java index 2d206e909..d06cf25dc 100644 --- a/codegen/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/SmithyGoDependency.java +++ b/codegen/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/SmithyGoDependency.java @@ -63,6 +63,7 @@ public final class SmithyGoDependency { public static final GoDependency SMITHY_DOCUMENT = smithy("document", "smithydocument"); public static final GoDependency SMITHY_DOCUMENT_JSON = smithy("document/json", "smithydocumentjson"); public static final GoDependency SMITHY_SYNC = smithy("sync", "smithysync"); + public static final GoDependency SMITHY_AUTH = smithy("auth", "smithyauth"); public static final GoDependency SMITHY_AUTH_BEARER = smithy("auth/bearer"); public static final GoDependency SMITHY_ENDPOINTS = smithy("endpoints", "smithyendpoints"); public static final GoDependency SMITHY_ENDPOINT_RULESFN = smithy("endpoints/private/rulesfn"); diff --git a/codegen/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/SmithyGoTypes.java b/codegen/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/SmithyGoTypes.java index 646f76713..7743a9360 100644 --- a/codegen/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/SmithyGoTypes.java +++ b/codegen/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/SmithyGoTypes.java @@ -24,6 +24,10 @@ public final class SmithyGoTypes { private SmithyGoTypes() { } + public static final class Smithy { + public static final Symbol Properties = SmithyGoDependency.SMITHY.pointableSymbol("Properties"); + } + public static final class Ptr { public static final Symbol String = SmithyGoDependency.SMITHY_PTR.valueSymbol("String"); public static final Symbol Bool = SmithyGoDependency.SMITHY_PTR.valueSymbol("Bool"); @@ -40,6 +44,18 @@ public static final class Middleware { public static final class Transport { public static final class Http { public static final Symbol Request = SmithyGoDependency.SMITHY_HTTP_TRANSPORT.pointableSymbol("Request"); + + public static final Symbol NewSigV4Option = SmithyGoDependency.SMITHY_HTTP_TRANSPORT.valueSymbol("NewSigV4Option"); + public static final Symbol NewSigV4AOption = SmithyGoDependency.SMITHY_HTTP_TRANSPORT.valueSymbol("NewSigV4AOption"); + public static final Symbol NewBearerOption = SmithyGoDependency.SMITHY_HTTP_TRANSPORT.valueSymbol("NewBearerOption"); + public static final Symbol NewAnonymousOption = SmithyGoDependency.SMITHY_HTTP_TRANSPORT.valueSymbol("NewAnonymousOption"); + + public static final Symbol SigV4Properties = SmithyGoDependency.SMITHY_HTTP_TRANSPORT.pointableSymbol("SigV4Properties"); + public static final Symbol SigV4AProperties = SmithyGoDependency.SMITHY_HTTP_TRANSPORT.pointableSymbol("SigV4AProperties"); } } + + public static final class Auth { + public static final Symbol Option = SmithyGoDependency.SMITHY_AUTH.pointableSymbol("Option"); + } } diff --git a/codegen/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/auth/AuthGenerator.java b/codegen/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/auth/AuthGenerator.java index dcbc0f87a..ba43f238a 100644 --- a/codegen/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/auth/AuthGenerator.java +++ b/codegen/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/auth/AuthGenerator.java @@ -36,6 +36,13 @@ public void generate() { context.getWriter().get() .write("$W", new AuthParametersGenerator(context).generate()) .write("") - .write("$W", new AuthParametersResolverGenerator(context).generate()); + .write("$W", new AuthParametersResolverGenerator(context).generate()) + .write("") + .write("$W", getResolverGenerator().generate()); + } + + // TODO(i&a): allow consuming generators to overwrite + private AuthSchemeResolverGenerator getResolverGenerator() { + return new AuthSchemeResolverGenerator(context); } } diff --git a/codegen/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/auth/AuthSchemeResolverGenerator.java b/codegen/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/auth/AuthSchemeResolverGenerator.java new file mode 100644 index 000000000..46befd07b --- /dev/null +++ b/codegen/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/auth/AuthSchemeResolverGenerator.java @@ -0,0 +1,202 @@ +/* + * Copyright 2023 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.go.codegen.auth; + +import static software.amazon.smithy.go.codegen.GoWriter.emptyGoTemplate; +import static software.amazon.smithy.go.codegen.GoWriter.goDocTemplate; +import static software.amazon.smithy.go.codegen.GoWriter.goTemplate; + +import java.util.Map; +import java.util.stream.Collectors; +import software.amazon.smithy.aws.traits.auth.UnsignedPayloadTrait; +import software.amazon.smithy.go.codegen.GoStdlibTypes; +import software.amazon.smithy.go.codegen.GoWriter; +import software.amazon.smithy.go.codegen.SmithyGoTypes; +import software.amazon.smithy.go.codegen.integration.AuthSchemeDefinition; +import software.amazon.smithy.go.codegen.integration.ProtocolGenerator; +import software.amazon.smithy.model.knowledge.ServiceIndex; +import software.amazon.smithy.model.knowledge.TopDownIndex; +import software.amazon.smithy.model.shapes.OperationShape; +import software.amazon.smithy.model.shapes.ShapeId; +import software.amazon.smithy.utils.MapUtils; + +/** + * Implements modeled auth scheme resolver generation. + */ +public class AuthSchemeResolverGenerator { + public static final String INTERFACE_NAME = "AuthSchemeResolver"; + public static final String DEFAULT_NAME = "defaultAuthSchemeResolver"; + + private final ProtocolGenerator.GenerationContext context; + private final ServiceIndex serviceIndex; + private final Map schemeDefinitions; + + public AuthSchemeResolverGenerator(ProtocolGenerator.GenerationContext context) { + this.context = context; + this.serviceIndex = ServiceIndex.of(context.getModel()); + this.schemeDefinitions = context.getIntegrations().stream() + .flatMap(it -> it.getClientPlugins(context.getModel(), context.getService()).stream()) + .flatMap(it -> it.getAuthSchemeDefinitions().entrySet().stream()) + .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); + } + + // an operation has auth overrides if any of the following are true: + // 1. its list of supported schemes differs from that of the service + // 2. its auth optionality differs from that of the service (covered by checking [1] w/ NO_AUTH_AWARE) + // 3. it has an unsigned payload + private boolean hasAuthOverrides(OperationShape operation) { + var serviceSchemes = serviceIndex + .getEffectiveAuthSchemes(context.getService(), ServiceIndex.AuthSchemeMode.NO_AUTH_AWARE) + .keySet(); + var operationSchemes = serviceIndex + .getEffectiveAuthSchemes(context.getService(), operation, ServiceIndex.AuthSchemeMode.NO_AUTH_AWARE) + .keySet(); + return !serviceSchemes.equals(operationSchemes) || operation.hasTrait(UnsignedPayloadTrait.class); + } + + public GoWriter.Writable generate() { + return goTemplate(""" + $W + + $W + """, generateInterface(), generateDefault()); + } + + private GoWriter.Writable generateInterface() { + return goTemplate(""" + $W + type $L interface { + ResolveAuthSchemes($T, *$L) ([]$P, error) + } + """, + generateDocs(), + INTERFACE_NAME, + GoStdlibTypes.Context.Context, + AuthParametersGenerator.STRUCT_NAME, + SmithyGoTypes.Auth.Option); + } + + private GoWriter.Writable generateDocs() { + return goDocTemplate("AuthSchemeResolver returns a set of possible authentication options for an " + + "operation."); + } + + private GoWriter.Writable generateDefault() { + return goTemplate(""" + $W + + $W + """, + generateDefaultStruct(), + generateDefaultResolve()); + } + + private GoWriter.Writable generateDefaultStruct() { + return goTemplate(""" + type $1L struct{} + + var _ $2L = (*$1L)(nil) + """, DEFAULT_NAME, INTERFACE_NAME); + } + + private GoWriter.Writable generateDefaultResolve() { + return goTemplate(""" + func (*$receiver:L) ResolveAuthSchemes(ctx $ctx:L, params *$params:L) ([]$options:P, error) { + if overrides, ok := operationAuthOptions[params.Operation]; ok { + return overrides(params), nil + } + return serviceAuthOptions(params), nil + } + + $opAuthOptions:W + + $svcAuthOptions:W + """, MapUtils.of( + "receiver", DEFAULT_NAME, + "ctx", GoStdlibTypes.Context.Context, + "params", AuthParametersGenerator.STRUCT_NAME, + "options", SmithyGoTypes.Auth.Option, + "opAuthOptions", generateOperationAuthOptions(), + "svcAuthOptions", generateServiceAuthOptions())); + } + + private GoWriter.Writable generateOperationAuthOptions() { + var options = new GoWriter.ChainWritable(); + TopDownIndex.of(context.getModel()) + .getContainedOperations(context.getService()).stream() + .filter(this::hasAuthOverrides) + .forEach(it -> { + options.add(generateOperationAuthOptionsEntry(it)); + }); + + return goTemplate(""" + var operationAuthOptions = map[string]func(*$L) []$P{ + $W + } + """, + AuthParametersGenerator.STRUCT_NAME, + SmithyGoTypes.Auth.Option, + options.compose()); + } + + private GoWriter.Writable generateOperationAuthOptionsEntry(OperationShape operation) { + var options = new GoWriter.ChainWritable(); + serviceIndex + .getEffectiveAuthSchemes(context.getService(), operation, ServiceIndex.AuthSchemeMode.NO_AUTH_AWARE) + .entrySet().stream() + .filter(it -> schemeDefinitions.containsKey(it.getKey())) + .forEach(it -> { + var definition = schemeDefinitions.get(it.getKey()); + options.add(definition.generateOperationOption(context, operation)); + }); + + return options.isEmpty() + ? emptyGoTemplate() + : goTemplate(""" + $1S: func(params *$2L) []$3P { + return []$3P{ + $4W + } + },""", + operation.getId().getName(), + AuthParametersGenerator.STRUCT_NAME, + SmithyGoTypes.Auth.Option, + options.compose()); + } + + private GoWriter.Writable generateServiceAuthOptions() { + var options = new GoWriter.ChainWritable(); + serviceIndex + .getEffectiveAuthSchemes(context.getService(), ServiceIndex.AuthSchemeMode.NO_AUTH_AWARE) + .entrySet().stream() + .filter(it -> schemeDefinitions.containsKey(it.getKey())) + .forEach(it -> { + var definition = schemeDefinitions.get(it.getKey()); + options.add(definition.generateServiceOption(context, context.getService())); + }); + + return goTemplate(""" + func serviceAuthOptions(params *$1L) []$2P { + return []$2P{ + $3W + } + } + """, + AuthParametersGenerator.STRUCT_NAME, + SmithyGoTypes.Auth.Option, + options.compose()); + } +} diff --git a/codegen/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/endpoints/EndpointParameterBindingsGenerator.java b/codegen/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/endpoints/EndpointParameterBindingsGenerator.java index 6fabbc9e7..fc7a160fd 100644 --- a/codegen/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/endpoints/EndpointParameterBindingsGenerator.java +++ b/codegen/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/endpoints/EndpointParameterBindingsGenerator.java @@ -19,6 +19,8 @@ import java.util.ArrayList; import java.util.HashMap; +import java.util.Map; +import java.util.stream.Collectors; import software.amazon.smithy.go.codegen.GoWriter; import software.amazon.smithy.go.codegen.integration.ProtocolGenerator; import software.amazon.smithy.rulesengine.language.syntax.parameters.Parameter; @@ -32,8 +34,14 @@ public class EndpointParameterBindingsGenerator { private final ProtocolGenerator.GenerationContext context; + private final Map builtinBindings; + public EndpointParameterBindingsGenerator(ProtocolGenerator.GenerationContext context) { this.context = context; + this.builtinBindings = context.getIntegrations().stream() + .flatMap(it -> it.getClientPlugins(context.getModel(), context.getService()).stream()) + .flatMap(it -> it.getEndpointBuiltinBindings().entrySet().stream()) + .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); } public GoWriter.Writable generate() { @@ -81,7 +89,7 @@ private GoWriter.Writable generateBuiltinBindings() { writer.write( "params.$L = $W", EndpointParametersGenerator.getExportedParameterName(param), - bindings.get(param.getBuiltIn().get())); + builtinBindings.get(param.getBuiltIn().get())); } }; } diff --git a/codegen/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/integration/AuthSchemeDefinition.java b/codegen/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/integration/AuthSchemeDefinition.java new file mode 100644 index 000000000..56bfb75a9 --- /dev/null +++ b/codegen/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/integration/AuthSchemeDefinition.java @@ -0,0 +1,38 @@ +/* + * Copyright 2023 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.go.codegen.integration; + +import software.amazon.smithy.go.codegen.GoWriter; +import software.amazon.smithy.model.shapes.OperationShape; +import software.amazon.smithy.model.shapes.ServiceShape; + +/** + * Defines code generation for a modeled auth scheme. + */ +public interface AuthSchemeDefinition { + /** + * Generates the service default option for this scheme. + */ + GoWriter.Writable generateServiceOption(ProtocolGenerator.GenerationContext context, ServiceShape service); + + /** + * Generates an operation-specific option for this scheme. This will only be called when the generator encounters + * an operation with auth overrides. + */ + GoWriter.Writable generateOperationOption(ProtocolGenerator.GenerationContext context, OperationShape operation); +} diff --git a/codegen/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/integration/RuntimeClientPlugin.java b/codegen/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/integration/RuntimeClientPlugin.java index bf35f214d..94f499649 100644 --- a/codegen/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/integration/RuntimeClientPlugin.java +++ b/codegen/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/integration/RuntimeClientPlugin.java @@ -29,6 +29,7 @@ import software.amazon.smithy.model.Model; import software.amazon.smithy.model.shapes.OperationShape; import software.amazon.smithy.model.shapes.ServiceShape; +import software.amazon.smithy.model.shapes.ShapeId; import software.amazon.smithy.utils.SmithyBuilder; import software.amazon.smithy.utils.ToSmithyBuilder; @@ -52,6 +53,7 @@ public final class RuntimeClientPlugin implements ToSmithyBuilder authParameterResolvers; private final MiddlewareRegistrar registerMiddleware; private final Map endpointBuiltinBindings; + private final Map authSchemeDefinitions; private RuntimeClientPlugin(Builder builder) { operationPredicate = builder.operationPredicate; @@ -64,6 +66,7 @@ private RuntimeClientPlugin(Builder builder) { authParameterResolvers = builder.authParameterResolvers; configFieldResolvers = builder.configFieldResolvers; endpointBuiltinBindings = builder.endpointBuiltinBindings; + authSchemeDefinitions = builder.authSchemeDefinitions; } @FunctionalInterface @@ -119,6 +122,14 @@ public Map getEndpointBuiltinBindings() { return endpointBuiltinBindings; } + /** + * Gets the registered auth scheme codegen definitions. + * @return the definitions. + */ + public Map getAuthSchemeDefinitions() { + return authSchemeDefinitions; + } + /** * Gets the optionally present middleware registrar object that resolves to middleware registering function. * @@ -230,6 +241,7 @@ public static final class Builder implements SmithyBuilder private Set authParameterResolvers = new HashSet<>(); private Map endpointBuiltinBindings = new HashMap<>(); private MiddlewareRegistrar registerMiddleware; + private Map authSchemeDefinitions = new HashMap<>(); @Override public RuntimeClientPlugin build() { @@ -473,5 +485,16 @@ public Builder addEndpointBuiltinBinding(String name, GoWriter.Writable binding) this.endpointBuiltinBindings.put(name, binding); return this; } + + /** + * Registers a codegen definition for a modeled auth scheme. + * @param schemeId The scheme id. + * @param definition The codegen definition. + * @return Returns the builder. + */ + public Builder addAuthSchemeDefinition(ShapeId schemeId, AuthSchemeDefinition definition) { + this.authSchemeDefinitions.put(schemeId, definition); + return this; + } } } diff --git a/codegen/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/integration/auth/AnonymousAuthScheme.java b/codegen/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/integration/auth/AnonymousAuthScheme.java new file mode 100644 index 000000000..c97bc81d9 --- /dev/null +++ b/codegen/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/integration/auth/AnonymousAuthScheme.java @@ -0,0 +1,36 @@ +/* + * Copyright 2023 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.go.codegen.integration.auth; + +import java.util.List; +import software.amazon.smithy.go.codegen.integration.AuthSchemeDefinition; +import software.amazon.smithy.go.codegen.integration.GoIntegration; +import software.amazon.smithy.go.codegen.integration.RuntimeClientPlugin; +import software.amazon.smithy.model.traits.synthetic.NoAuthTrait; +import software.amazon.smithy.utils.ListUtils; + +public class AnonymousAuthScheme implements GoIntegration { + private static final AuthSchemeDefinition ANONYMOUS_DEFINITION = new AnonymousDefinition(); + + @Override + public List getClientPlugins() { + return ListUtils.of( + RuntimeClientPlugin.builder() + .addAuthSchemeDefinition(NoAuthTrait.ID, ANONYMOUS_DEFINITION) + .build() + ); + } +} diff --git a/codegen/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/integration/auth/AnonymousDefinition.java b/codegen/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/integration/auth/AnonymousDefinition.java new file mode 100644 index 000000000..d05daa509 --- /dev/null +++ b/codegen/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/integration/auth/AnonymousDefinition.java @@ -0,0 +1,40 @@ +/* + * Copyright 2023 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.go.codegen.integration.auth; + +import static software.amazon.smithy.go.codegen.GoWriter.goTemplate; + +import software.amazon.smithy.go.codegen.GoWriter; +import software.amazon.smithy.go.codegen.SmithyGoTypes; +import software.amazon.smithy.go.codegen.integration.AuthSchemeDefinition; +import software.amazon.smithy.go.codegen.integration.ProtocolGenerator; +import software.amazon.smithy.model.shapes.OperationShape; +import software.amazon.smithy.model.shapes.ServiceShape; + +/** + * Implements codegen for smithy.api#noAuth. + */ +public class AnonymousDefinition implements AuthSchemeDefinition { + @Override + public GoWriter.Writable generateServiceOption(ProtocolGenerator.GenerationContext c, ServiceShape s) { + return goTemplate("$T(),", SmithyGoTypes.Transport.Http.NewAnonymousOption); + } + + @Override + public GoWriter.Writable generateOperationOption(ProtocolGenerator.GenerationContext c, OperationShape o) { + return goTemplate("$T(),", SmithyGoTypes.Transport.Http.NewAnonymousOption); + } +} diff --git a/codegen/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/integration/auth/HttpBearerAuth.java b/codegen/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/integration/auth/HttpBearerAuth.java index 5ec697581..94c9cf66d 100644 --- a/codegen/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/integration/auth/HttpBearerAuth.java +++ b/codegen/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/integration/auth/HttpBearerAuth.java @@ -23,6 +23,7 @@ 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.AuthSchemeDefinition; import software.amazon.smithy.go.codegen.integration.ConfigField; import software.amazon.smithy.go.codegen.integration.ConfigFieldResolver; import software.amazon.smithy.go.codegen.integration.GoIntegration; @@ -48,6 +49,7 @@ public class HttpBearerAuth implements GoIntegration { private static final String NEW_DEFAULT_SIGNER_NAME = "newDefault" + SIGNER_OPTION_NAME; private static final String SIGNER_RESOLVER_NAME = "resolve" + SIGNER_OPTION_NAME; private static final String REGISTER_MIDDLEWARE_NAME = "add" + SIGNER_OPTION_NAME + "Middleware"; + private static final AuthSchemeDefinition HTTP_BEARER_DEFINITION = new HttpBearerDefinition(); @Override public void writeAdditionalFiles( @@ -162,6 +164,10 @@ public List getClientPlugins() { REGISTER_MIDDLEWARE_NAME).build()) .useClientOptions() .build()) + .build(), + + RuntimeClientPlugin.builder() + .addAuthSchemeDefinition(HttpBearerAuthTrait.ID, HTTP_BEARER_DEFINITION) .build() ); } diff --git a/codegen/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/integration/auth/HttpBearerDefinition.java b/codegen/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/integration/auth/HttpBearerDefinition.java new file mode 100644 index 000000000..6ed4546ea --- /dev/null +++ b/codegen/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/integration/auth/HttpBearerDefinition.java @@ -0,0 +1,40 @@ +/* + * Copyright 2023 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.go.codegen.integration.auth; + +import static software.amazon.smithy.go.codegen.GoWriter.goTemplate; + +import software.amazon.smithy.go.codegen.GoWriter; +import software.amazon.smithy.go.codegen.SmithyGoTypes; +import software.amazon.smithy.go.codegen.integration.AuthSchemeDefinition; +import software.amazon.smithy.go.codegen.integration.ProtocolGenerator; +import software.amazon.smithy.model.shapes.OperationShape; +import software.amazon.smithy.model.shapes.ServiceShape; + +/** + * Implements codegen for smithy.api#httpBearerAuth. + */ +public class HttpBearerDefinition implements AuthSchemeDefinition { + @Override + public GoWriter.Writable generateServiceOption(ProtocolGenerator.GenerationContext context, ServiceShape service) { + return goTemplate("$T(),", SmithyGoTypes.Transport.Http.NewBearerOption); + } + + @Override + public GoWriter.Writable generateOperationOption(ProtocolGenerator.GenerationContext c, OperationShape o) { + return goTemplate("$T(),", SmithyGoTypes.Transport.Http.NewBearerOption); + } +} diff --git a/codegen/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/integration/SigV4AuthParameters.java b/codegen/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/integration/auth/SigV4AuthScheme.java similarity index 55% rename from codegen/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/integration/SigV4AuthParameters.java rename to codegen/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/integration/auth/SigV4AuthScheme.java index a97ec5ad6..06dd77b42 100644 --- a/codegen/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/integration/SigV4AuthParameters.java +++ b/codegen/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/integration/auth/SigV4AuthScheme.java @@ -1,5 +1,5 @@ /* - * Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * Copyright 2023 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. @@ -13,28 +13,37 @@ * permissions and limitations under the License. */ -package software.amazon.smithy.go.codegen.integration; +package software.amazon.smithy.go.codegen.integration.auth; import java.util.List; +import software.amazon.smithy.aws.traits.auth.SigV4Trait; import software.amazon.smithy.go.codegen.auth.AuthParameter; +import software.amazon.smithy.go.codegen.integration.AuthSchemeDefinition; +import software.amazon.smithy.go.codegen.integration.GoIntegration; +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.utils.ListUtils; /** - * Adds the input region as an auth resolution parameter for SigV4x-based services. + * Code generation for SigV4. */ -public class SigV4AuthParameters implements GoIntegration { +public class SigV4AuthScheme implements GoIntegration { + private static final AuthSchemeDefinition SIGV4_DEFINITION = new SigV4Definition(); + private boolean isSigV4Service(Model model, ServiceShape service) { - return service.hasTrait("aws.auth#sigv4"); + return service.hasTrait(SigV4Trait.class); } @Override public List getClientPlugins() { + // FUTURE: add default Region client option and resolver - we need a more structured way of suppressing + // elements of a GoIntegration before we do so, for now those live on the SDK side return ListUtils.of( RuntimeClientPlugin.builder() .servicePredicate(this::isSigV4Service) .addAuthParameter(AuthParameter.REGION) + .addAuthSchemeDefinition(SigV4Trait.ID, SIGV4_DEFINITION) .build() ); } diff --git a/codegen/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/integration/auth/SigV4Definition.java b/codegen/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/integration/auth/SigV4Definition.java new file mode 100644 index 000000000..05ca66b98 --- /dev/null +++ b/codegen/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/integration/auth/SigV4Definition.java @@ -0,0 +1,70 @@ +/* + * Copyright 2023 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.go.codegen.integration.auth; + +import static software.amazon.smithy.go.codegen.GoWriter.emptyGoTemplate; +import static software.amazon.smithy.go.codegen.GoWriter.goTemplate; + +import software.amazon.smithy.aws.traits.auth.SigV4Trait; +import software.amazon.smithy.aws.traits.auth.UnsignedPayloadTrait; +import software.amazon.smithy.go.codegen.GoWriter; +import software.amazon.smithy.go.codegen.SmithyGoTypes; +import software.amazon.smithy.go.codegen.integration.AuthSchemeDefinition; +import software.amazon.smithy.go.codegen.integration.ProtocolGenerator; +import software.amazon.smithy.model.shapes.OperationShape; +import software.amazon.smithy.model.shapes.ServiceShape; + +/** + * Implements codegen for aws.auth#sigv4. + */ +public class SigV4Definition implements AuthSchemeDefinition { + @Override + public GoWriter.Writable generateServiceOption(ProtocolGenerator.GenerationContext context, ServiceShape service) { + var trait = service.expectTrait(SigV4Trait.class); + return goTemplate(""" + $T(func (props $P) { + props.SigningName = $S + props.SigningRegion = params.Region + }),""", + SmithyGoTypes.Transport.Http.NewSigV4Option, + SmithyGoTypes.Transport.Http.SigV4Properties, + trait.getName()); + } + + @Override + public GoWriter.Writable generateOperationOption( + ProtocolGenerator.GenerationContext context, + OperationShape operation + ) { + var trait = context.getService().expectTrait(SigV4Trait.class); + return goTemplate(""" + $T(func (props $P) { + props.SigningName = $S + props.SigningRegion = params.Region + $W + }),""", + SmithyGoTypes.Transport.Http.NewSigV4Option, + SmithyGoTypes.Transport.Http.SigV4Properties, + trait.getName(), + generateIsUnsignedPayload(operation)); + } + + private GoWriter.Writable generateIsUnsignedPayload(OperationShape operation) { + return operation.hasTrait(UnsignedPayloadTrait.class) + ? goTemplate("props.IsUnsignedPayload = true") + : emptyGoTemplate(); + } +} diff --git a/codegen/smithy-go-codegen/src/main/resources/META-INF/services/software.amazon.smithy.go.codegen.integration.GoIntegration b/codegen/smithy-go-codegen/src/main/resources/META-INF/services/software.amazon.smithy.go.codegen.integration.GoIntegration index 369a255ad..ec8358730 100644 --- a/codegen/smithy-go-codegen/src/main/resources/META-INF/services/software.amazon.smithy.go.codegen.integration.GoIntegration +++ b/codegen/smithy-go-codegen/src/main/resources/META-INF/services/software.amazon.smithy.go.codegen.integration.GoIntegration @@ -1,4 +1,3 @@ -software.amazon.smithy.go.codegen.integration.auth.HttpBearerAuth software.amazon.smithy.go.codegen.integration.ValidationGenerator software.amazon.smithy.go.codegen.integration.IdempotencyTokenMiddlewareGenerator software.amazon.smithy.go.codegen.integration.AddChecksumRequiredMiddleware @@ -8,5 +7,9 @@ software.amazon.smithy.go.codegen.integration.OperationInterfaceGenerator software.amazon.smithy.go.codegen.integration.Paginators software.amazon.smithy.go.codegen.integration.Waiters software.amazon.smithy.go.codegen.integration.ClientLogger -software.amazon.smithy.go.codegen.integration.SigV4AuthParameters software.amazon.smithy.go.codegen.endpoints.EndpointClientPluginsGenerator + +# modeled auth schemes +software.amazon.smithy.go.codegen.integration.auth.SigV4AuthScheme +software.amazon.smithy.go.codegen.integration.auth.HttpBearerAuth +software.amazon.smithy.go.codegen.integration.auth.AnonymousAuthScheme diff --git a/properties.go b/properties.go index 17d659c53..fb72c788f 100644 --- a/properties.go +++ b/properties.go @@ -7,12 +7,10 @@ type PropertiesReader interface { } // Properties provides storing and reading metadata values. Keys may be any -// comparable value type. Get and set will panic if key is not a comparable -// value type. +// comparable value type. Get and Set will panic if a key is not comparable. // -// Properties uses lazy initialization, and Set method must be called as an -// addressable value, or pointer. Not doing so may cause key/value pair to not -// be set. +// The zero value for a Properties instance is ready for reads/writes without +// any additional initialization. type Properties struct { values map[interface{}]interface{} } @@ -28,10 +26,6 @@ func (m *Properties) Get(key interface{}) interface{} { // Set stores the value pointed to by the key. If a value already exists at // that key it will be replaced with the new value. // -// Set method must be called as an addressable value, or pointer. If Set is not -// called as an addressable value or pointer, the key value pair being set may -// be lost. -// // Panics if the key type is not comparable. func (m *Properties) Set(key, value interface{}) { if m.values == nil { diff --git a/transport/http/auth.go b/transport/http/auth.go new file mode 100644 index 000000000..c37c7b68c --- /dev/null +++ b/transport/http/auth.go @@ -0,0 +1,22 @@ +package http + +import ( + "context" + "net/http" + + smithy "github.com/aws/smithy-go" + "github.com/aws/smithy-go/auth" +) + +// AuthScheme defines an HTTP authentication scheme. +type AuthScheme interface { + SchemeID() string + IdentityResolver(auth.IdentityResolverOptions) auth.IdentityResolver + Signer() Signer +} + +// Signer defines the interface through which HTTP requests are supplemented +// with an Identity. +type Signer interface { + SignRequest(context.Context, *http.Request, auth.Identity, *smithy.Properties) error +} diff --git a/transport/http/auth_options.go b/transport/http/auth_options.go new file mode 100644 index 000000000..1515979ac --- /dev/null +++ b/transport/http/auth_options.go @@ -0,0 +1,84 @@ +package http + +import ( + smithy "github.com/aws/smithy-go" + "github.com/aws/smithy-go/auth" +) + +// NewSigV4Option creates a SigV4 auth Option from an input configuration. +func NewSigV4Option(propFns ...func(*SigV4Properties)) *auth.Option { + var props SigV4Properties + for _, f := range propFns { + f(&props) + } + + return &auth.Option{ + SchemeID: SchemeIDSigV4, + SignerProperties: props.toSignerProperties(), + } +} + +// SigV4Properties represent the inputs to the SigV4 auth scheme. +type SigV4Properties struct { + SigningName string + SigningRegion string + IsUnsignedPayload bool +} + +func (p *SigV4Properties) toSignerProperties() smithy.Properties { + var props smithy.Properties + SetSigV4SigningName(&props, p.SigningName) + SetSigV4SigningRegion(&props, p.SigningRegion) + SetIsUnsignedPayload(&props, p.IsUnsignedPayload) + return props +} + +// NewSigV4AOption creates a SigV4A auth Option from an input configuration. +func NewSigV4AOption(propFns ...func(*SigV4AProperties)) *auth.Option { + var props SigV4AProperties + for _, f := range propFns { + f(&props) + } + + return &auth.Option{ + SchemeID: SchemeIDSigV4A, + SignerProperties: props.toSignerProperties(), + } +} + +// SigV4AProperties represent the inputs to the SigV4A auth scheme. +type SigV4AProperties struct { + SigningName string + SigningRegions []string + IsUnsignedPayload bool +} + +func (p *SigV4AProperties) toSignerProperties() smithy.Properties { + var props smithy.Properties + SetSigV4ASigningName(&props, p.SigningName) + SetSigV4ASigningRegions(&props, p.SigningRegions) + SetIsUnsignedPayload(&props, p.IsUnsignedPayload) + return props +} + +// NewBearerOption creates a Bearer auth Option. +// +// The Bearer auth scheme currently has no configuration, so the inputs to this +// API will be ignored. +func NewBearerOption(propFns ...func(*BearerProperties)) *auth.Option { + return &auth.Option{SchemeID: SchemeIDBearer} +} + +// BearerProperties represents a configuration of the Bearer auth scheme. +type BearerProperties struct{} + +// NewAnonymousOption creates an Anonymous auth Option. +// +// The Anonymous auth scheme currently has no configuration, so the inputs to +// this API will be ignored. +func NewAnonymousOption(propFns ...func(*AnonymousProperties)) *auth.Option { + return &auth.Option{SchemeID: SchemeIDAnonymous} +} + +// AnonymousProperties represents a configuration of the Anonymous auth scheme. +type AnonymousProperties struct{} diff --git a/transport/http/auth_schemes.go b/transport/http/auth_schemes.go new file mode 100644 index 000000000..34ace31fc --- /dev/null +++ b/transport/http/auth_schemes.go @@ -0,0 +1,84 @@ +package http + +import ( + "context" + "net/http" + + smithy "github.com/aws/smithy-go" + "github.com/aws/smithy-go/auth" +) + +const ( + // SchemeIDSigV4 identifies the SigV4 auth scheme. + SchemeIDSigV4 = "aws.auth#sigv4" + + // SchemeIDSigV4A identifies the SigV4A auth scheme. + SchemeIDSigV4A = "aws.auth#sigv4a" + + // SchemeIDBearer identifies the HTTP Bearer auth scheme. + SchemeIDBearer = "smithy.api#httpBearerAuth" + + // SchemeIDAnonymous identifies the anonymous or "no-auth" scheme. + SchemeIDAnonymous = "smithy.api#noAuth" +) + +// NewSigV4Scheme returns a SigV4 auth scheme that uses the given Signer. +func NewSigV4Scheme(signer Signer) AuthScheme { + return &authScheme{ + schemeID: SchemeIDSigV4, + signer: signer, + } +} + +// NewSigV4AScheme returns a SigV4A auth scheme that uses the given Signer. +func NewSigV4AScheme(signer Signer) AuthScheme { + return &authScheme{ + schemeID: SchemeIDSigV4A, + signer: signer, + } +} + +// NewBearerScheme returns an HTTP bearer auth scheme that uses the given Signer. +func NewBearerScheme(signer Signer) AuthScheme { + return &authScheme{ + schemeID: SchemeIDBearer, + signer: signer, + } +} + +// NewBearerScheme returns an anonymous auth scheme. +func NewAnonymousScheme() AuthScheme { + return &authScheme{ + schemeID: SchemeIDAnonymous, + signer: &nopSigner{}, + } +} + +// authScheme is parameterized to generically implement the exported AuthScheme +// interface +type authScheme struct { + schemeID string + signer Signer +} + +var _ AuthScheme = (*authScheme)(nil) + +func (s *authScheme) SchemeID() string { + return s.schemeID +} + +func (s *authScheme) IdentityResolver(o auth.IdentityResolverOptions) auth.IdentityResolver { + return o.GetIdentityResolver(s.schemeID) +} + +func (s *authScheme) Signer() Signer { + return s.signer +} + +type nopSigner struct{} + +var _ Signer = (*nopSigner)(nil) + +func (*nopSigner) SignRequest(context.Context, *http.Request, auth.Identity, *smithy.Properties) error { + return nil +} diff --git a/transport/http/properties.go b/transport/http/properties.go new file mode 100644 index 000000000..2608a779d --- /dev/null +++ b/transport/http/properties.go @@ -0,0 +1,68 @@ +package http + +import smithy "github.com/aws/smithy-go" + +var ( + sigV4SigningNameKey struct{} + sigV4SigningRegionKey struct{} + + sigV4ASigningNameKey struct{} + sigV4ASigningRegionsKey struct{} + + isUnsignedPayloadKey struct{} +) + +// GetSigV4SigningName gets the signing name from Properties. +func GetSigV4SigningName(p *smithy.Properties) (string, bool) { + v, ok := p.Get(sigV4SigningNameKey).(string) + return v, ok +} + +// SetSigV4SigningName sets the signing name on Properties. +func SetSigV4SigningName(p *smithy.Properties, name string) { + p.Set(sigV4SigningNameKey, name) +} + +// GetSigV4SigningRegion gets the signing region from Properties. +func GetSigV4SigningRegion(p *smithy.Properties) (string, bool) { + v, ok := p.Get(sigV4SigningRegionKey).(string) + return v, ok +} + +// SetSigV4SigningRegion sets the signing region on Properties. +func SetSigV4SigningRegion(p *smithy.Properties, region string) { + p.Set(sigV4SigningRegionKey, region) +} + +// GetSigV4ASigningName gets the v4a signing name from Properties. +func GetSigV4ASigningName(p *smithy.Properties) (string, bool) { + v, ok := p.Get(sigV4ASigningNameKey).(string) + return v, ok +} + +// SetSigV4ASigningName sets the signing name on Properties. +func SetSigV4ASigningName(p *smithy.Properties, name string) { + p.Set(sigV4ASigningNameKey, name) +} + +// GetSigV4ASigningRegion gets the v4a signing region set from Properties. +func GetSigV4ASigningRegions(p *smithy.Properties) ([]string, bool) { + v, ok := p.Get(sigV4ASigningRegionsKey).([]string) + return v, ok +} + +// SetSigV4ASigningRegions sets the v4a signing region set on Properties. +func SetSigV4ASigningRegions(p *smithy.Properties, regions []string) { + p.Set(sigV4ASigningRegionsKey, regions) +} + +// GetIsUnsignedPayload gets whether the payload is unsigned from Properties. +func GetIsUnsignedPayload(p *smithy.Properties) (bool, bool) { + v, ok := p.Get(isUnsignedPayloadKey).(bool) + return v, ok +} + +// SetIsUnsignedPayload sets whether the payload is unsigned on Properties. +func SetIsUnsignedPayload(p *smithy.Properties, isUnsignedPayload bool) { + p.Set(isUnsignedPayloadKey, isUnsignedPayload) +}