diff --git a/codegen/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/CodegenVisitor.java b/codegen/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/CodegenVisitor.java index 91e68b14e..0e817c65f 100644 --- a/codegen/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/CodegenVisitor.java +++ b/codegen/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/CodegenVisitor.java @@ -247,6 +247,11 @@ void execute() { protocolGenerator.generateEndpointResolution(context); }); + writers.useFileWriter("auth.go", settings.getModuleName(), writer -> { + ProtocolGenerator.GenerationContext context = contextBuilder.writer(writer).build(); + protocolGenerator.generateAuth(context); + }); + writers.useFileWriter("endpoints_test.go", settings.getModuleName(), writer -> { ProtocolGenerator.GenerationContext context = contextBuilder.writer(writer).build(); protocolGenerator.generateEndpointResolutionTests(context); diff --git a/codegen/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/GoUniverseTypes.java b/codegen/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/GoUniverseTypes.java index 6300dc0dc..0482f8b71 100644 --- a/codegen/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/GoUniverseTypes.java +++ b/codegen/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/GoUniverseTypes.java @@ -21,32 +21,33 @@ * Collection of Symbol constants for golang universe types. * See predeclared identifiers. */ +@SuppressWarnings("checkstyle:ConstantName") public final class GoUniverseTypes { - public static Symbol tAny = universe("any"); - public static Symbol tBool = universe("bool"); - public static Symbol tByte = universe("byte"); - public static Symbol tComparable = universe("comparable"); - - public static Symbol tComplex64 = universe("complex64"); - public static Symbol tComplex128 = universe("complex128"); - public static Symbol tError = universe("error"); - public static Symbol tFloat32 = universe("float32"); - public static Symbol tFloat64 = universe("float64"); - - public static Symbol tInt = universe("int"); - public static Symbol tInt8 = universe("int8"); - public static Symbol tInt16 = universe("int16"); - public static Symbol tInt32 = universe("int32"); - public static Symbol tInt64 = universe("int64"); - public static Symbol tRune = universe("rune"); - public static Symbol tString = universe("string"); - - public static Symbol tUint = universe("uint"); - public static Symbol tUint8 = universe("uint8"); - public static Symbol tUint16 = universe("uint16"); - public static Symbol tUint32 = universe("uint32"); - public static Symbol tUint64 = universe("uint64"); - public static Symbol tUintptr = universe("uintptr"); + public static final Symbol Any = universe("any"); + public static final Symbol Bool = universe("bool"); + public static final Symbol Byte = universe("byte"); + public static final Symbol Comparable = universe("comparable"); + + public static final Symbol Complex64 = universe("complex64"); + public static final Symbol Complex128 = universe("complex128"); + public static final Symbol Error = universe("error"); + public static final Symbol Float32 = universe("float32"); + public static final Symbol Float64 = universe("float64"); + + public static final Symbol Int = universe("int"); + public static final Symbol Int8 = universe("int8"); + public static final Symbol Int16 = universe("int16"); + public static final Symbol Int32 = universe("int32"); + public static final Symbol Int64 = universe("int64"); + public static final Symbol Rune = universe("rune"); + public static final Symbol String = universe("string"); + + public static final Symbol Uint = universe("uint"); + public static final Symbol Uint8 = universe("uint8"); + public static final Symbol Uint16 = universe("uint16"); + public static final Symbol Uint32 = universe("uint32"); + public static final Symbol Uint64 = universe("uint64"); + public static final Symbol Uintptr = universe("uintptr"); private GoUniverseTypes() {} diff --git a/codegen/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/OperationGenerator.java b/codegen/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/OperationGenerator.java index 6cd5b704f..c53b00444 100644 --- a/codegen/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/OperationGenerator.java +++ b/codegen/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/OperationGenerator.java @@ -130,6 +130,15 @@ public void run() { .renderStructure(() -> { }, true); + writer.write(""" + func (*$T) operationName() string { + return $S + } + """, + inputSymbol, + operationSymbol.getName() + ); + // The output structure gets a metadata member added. Symbol metadataSymbol = SymbolUtils.createValueSymbolBuilder("Metadata", SmithyGoDependency.SMITHY_MIDDLEWARE) .build(); 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 new file mode 100644 index 000000000..dcbc0f87a --- /dev/null +++ b/codegen/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/auth/AuthGenerator.java @@ -0,0 +1,41 @@ +/* + * 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 software.amazon.smithy.codegen.core.CodegenException; +import software.amazon.smithy.go.codegen.integration.ProtocolGenerator; + +/** + * Entry point into smithy client auth generation. + */ +public class AuthGenerator { + private final ProtocolGenerator.GenerationContext context; + + public AuthGenerator(ProtocolGenerator.GenerationContext context) { + this.context = context; + } + + public void generate() { + if (context.getWriter().isEmpty()) { + throw new CodegenException("writer is required"); + } + + context.getWriter().get() + .write("$W", new AuthParametersGenerator(context).generate()) + .write("") + .write("$W", new AuthParametersResolverGenerator(context).generate()); + } +} diff --git a/codegen/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/auth/AuthParameter.java b/codegen/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/auth/AuthParameter.java new file mode 100644 index 000000000..007a3b96d --- /dev/null +++ b/codegen/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/auth/AuthParameter.java @@ -0,0 +1,33 @@ +/* + * 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 software.amazon.smithy.codegen.core.Symbol; +import software.amazon.smithy.go.codegen.GoUniverseTypes; + +public record AuthParameter(String name, String docs, Symbol type) { + public static final AuthParameter OPERATION = new AuthParameter( + "Operation", + "The name of the operation being invoked.", + GoUniverseTypes.String + ); + + public static final AuthParameter REGION = new AuthParameter( + "Region", + "The region in which the operation is being invoked.", + GoUniverseTypes.String + ); +} diff --git a/codegen/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/auth/AuthParametersGenerator.java b/codegen/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/auth/AuthParametersGenerator.java new file mode 100644 index 000000000..70171b2fc --- /dev/null +++ b/codegen/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/auth/AuthParametersGenerator.java @@ -0,0 +1,99 @@ +/* + * 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.goDocTemplate; +import static software.amazon.smithy.go.codegen.GoWriter.goTemplate; + +import java.util.ArrayList; +import software.amazon.smithy.codegen.core.Symbol; +import software.amazon.smithy.go.codegen.GoWriter; +import software.amazon.smithy.go.codegen.SymbolUtils; +import software.amazon.smithy.go.codegen.integration.ProtocolGenerator; +import software.amazon.smithy.utils.ListUtils; +import software.amazon.smithy.utils.MapUtils; + +/** + * Generates auth scheme resolver parameters. + * By default, the only field that exists universally is the name of the operation being invoked. Services that use + * SigV4[A] will also have a field for the region. + * Additional parameters can be loaded via GoIntegration. + */ +public class AuthParametersGenerator { + public static final String STRUCT_NAME = "AuthResolverParameters"; + + public static final Symbol STRUCT_SYMBOL = SymbolUtils.createPointableSymbolBuilder(STRUCT_NAME).build(); + + private final ProtocolGenerator.GenerationContext context; + + private final ArrayList fields = new ArrayList<>( + ListUtils.of(AuthParameter.OPERATION) + ); + + public AuthParametersGenerator(ProtocolGenerator.GenerationContext context) { + this.context = context; + } + + public GoWriter.Writable generate() { + loadFields(); + + return goTemplate( + """ + $doc:W + type $name:L struct { + $fields:W + } + """, + MapUtils.of( + "doc", generateDocs(), + "name", STRUCT_NAME, + "fields", generateFields() + ) + ); + } + + private GoWriter.Writable generateDocs() { + return goDocTemplate( + "$name:L contains the set of inputs necessary for auth scheme resolution.", + MapUtils.of("name", STRUCT_NAME) + ); + } + + private GoWriter.Writable generateFields() { + return (writer) -> { + for (var field: fields) { + writer.write(""" + $W + $L $P + """, + goDocTemplate(field.docs()), + field.name(), + field.type() + ); + } + }; + } + + private void loadFields() { + for (var integration: context.getIntegrations()) { + var plugins = integration.getClientPlugins().stream().filter(it -> + it.matchesService(context.getModel(), context.getService())).toList(); + for (var plugin: plugins) { + fields.addAll(plugin.getAuthParameters()); + } + } + } +} diff --git a/codegen/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/auth/AuthParametersResolver.java b/codegen/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/auth/AuthParametersResolver.java new file mode 100644 index 000000000..b5e037dff --- /dev/null +++ b/codegen/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/auth/AuthParametersResolver.java @@ -0,0 +1,20 @@ +/* + * 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 software.amazon.smithy.codegen.core.Symbol; + +public record AuthParametersResolver(Symbol resolver) { } diff --git a/codegen/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/auth/AuthParametersResolverGenerator.java b/codegen/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/auth/AuthParametersResolverGenerator.java new file mode 100644 index 000000000..9b7452391 --- /dev/null +++ b/codegen/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/auth/AuthParametersResolverGenerator.java @@ -0,0 +1,96 @@ +/* + * 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.goTemplate; + +import java.util.ArrayList; +import software.amazon.smithy.codegen.core.Symbol; +import software.amazon.smithy.go.codegen.GoWriter; +import software.amazon.smithy.go.codegen.SymbolUtils; +import software.amazon.smithy.go.codegen.integration.ProtocolGenerator; +import software.amazon.smithy.utils.MapUtils; + +/** + * Generates a single method which binds auth scheme resolver parameters from operation input and client options. + * The only value bound by default is the operation name. Generators must load additional bindings through + * GoIntegration. + */ +public class AuthParametersResolverGenerator { + public static final String FUNC_NAME = "bindAuthResolverParams"; + + public static final Symbol FUNC_SYMBOL = SymbolUtils.createValueSymbolBuilder(FUNC_NAME).build(); + + private final ProtocolGenerator.GenerationContext context; + + private final ArrayList resolvers = new ArrayList<>(); + + public AuthParametersResolverGenerator(ProtocolGenerator.GenerationContext context) { + this.context = context; + } + + public GoWriter.Writable generate() { + loadResolvers(); + + return goTemplate(""" + $operationNamer:W + + func $name:L(input interface{}, options Options) $params:P { + params := &$params:T{ + Operation: input.(operationNamer).operationName(), + } + + $bindings:W + + return params + } + """, + MapUtils.of( + "name", FUNC_NAME, + "operationNamer", generateOperationNamer(), + "params", AuthParametersGenerator.STRUCT_SYMBOL, + "bindings", generateResolvers() + )); + } + + private GoWriter.Writable generateOperationNamer() { + return (writer) -> { + writer.write(""" + type operationNamer interface { + operationName() string + } + """); + }; + } + + private GoWriter.Writable generateResolvers() { + return (writer) -> { + for (var resolver: resolvers) { + writer.write("$T(params, input, options)", resolver.resolver()); + } + }; + } + + private void loadResolvers() { + for (var integration: context.getIntegrations()) { + var plugins = integration.getClientPlugins().stream().filter(it -> + it.matchesService(context.getModel(), context.getService())).toList(); + for (var plugin: plugins) { + resolvers.addAll(plugin.getAuthParameterResolvers()); + } + } + } +} diff --git a/codegen/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/integration/ProtocolGenerator.java b/codegen/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/integration/ProtocolGenerator.java index 9fed920f3..d43544f93 100644 --- a/codegen/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/integration/ProtocolGenerator.java +++ b/codegen/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/integration/ProtocolGenerator.java @@ -29,6 +29,7 @@ import software.amazon.smithy.go.codegen.GoSettings; import software.amazon.smithy.go.codegen.GoWriter; import software.amazon.smithy.go.codegen.Synthetic; +import software.amazon.smithy.go.codegen.auth.AuthGenerator; import software.amazon.smithy.go.codegen.endpoints.EndpointResolutionGenerator; import software.amazon.smithy.go.codegen.endpoints.FnGenerator; import software.amazon.smithy.model.Model; @@ -481,6 +482,15 @@ default void generateEndpointResolutionTests(GenerationContext context) { generator.generateTests(context); } + /** + * Generates smithy client auth components. + * + * @param context The generation context. + */ + default void generateAuth(GenerationContext context) { + new AuthGenerator(context).generate(); + } + /** * Context object used for service serialization and deserialization. */ 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 8b3b7075e..79cadd7f3 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 @@ -21,6 +21,8 @@ import java.util.Optional; import java.util.Set; import java.util.function.BiPredicate; +import software.amazon.smithy.go.codegen.auth.AuthParameter; +import software.amazon.smithy.go.codegen.auth.AuthParametersResolver; import software.amazon.smithy.model.Model; import software.amazon.smithy.model.shapes.OperationShape; import software.amazon.smithy.model.shapes.ServiceShape; @@ -43,6 +45,8 @@ public final class RuntimeClientPlugin implements ToSmithyBuilder configFieldResolvers; private final Set clientMembers; private final Set clientMemberResolvers; + private final Set authParameters; + private final Set authParameterResolvers; private final MiddlewareRegistrar registerMiddleware; private RuntimeClientPlugin(Builder builder) { @@ -52,6 +56,8 @@ private RuntimeClientPlugin(Builder builder) { registerMiddleware = builder.registerMiddleware; clientMembers = builder.clientMembers; clientMemberResolvers = builder.clientMemberResolvers; + authParameters = builder.authParameters; + authParameterResolvers = builder.authParameterResolvers; configFieldResolvers = builder.configFieldResolvers; } @@ -85,6 +91,22 @@ public Set getClientMemberResolvers() { return clientMemberResolvers; } + /** + * Gets the auth parameters that will be added by this plugin. + * @return the auth parameters. + */ + public Set getAuthParameters() { + return authParameters; + } + + /** + * Gets the auth parameter resolvers that will be added by this plugin. + * @return the auth parameter resolvers. + */ + public Set getAuthParameterResolvers() { + return authParameterResolvers; + } + /** * Gets the optionally present middleware registrar object that resolves to middleware registering function. * @@ -192,6 +214,8 @@ public static final class Builder implements SmithyBuilder private Set configFieldResolvers = new HashSet<>(); private Set clientMembers = new HashSet<>(); private Set clientMemberResolvers = new HashSet<>(); + private Set authParameters = new HashSet<>(); + private Set authParameterResolvers = new HashSet<>(); private MiddlewareRegistrar registerMiddleware; @Override @@ -403,5 +427,27 @@ public Builder addClientMemberResolver(ClientMemberResolver clientMemberResolver this.clientMemberResolvers.add(clientMemberResolver); return this; } + + /** + * Adds a field to the auth parameters. + * + * @param param The field. + * @return Returns the builder. + */ + public Builder addAuthParameter(AuthParameter param) { + this.authParameters.add(param); + return this; + } + + /** + * Adds a resolver for fields on auth parameters. + * + * @param resolver The auth field resolver. + * @return Returns the builder. + */ + public Builder addAuthParameterResolver(AuthParametersResolver resolver) { + this.authParameterResolvers.add(resolver); + return this; + } } } 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/SigV4AuthParameters.java new file mode 100644 index 000000000..a97ec5ad6 --- /dev/null +++ b/codegen/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/integration/SigV4AuthParameters.java @@ -0,0 +1,41 @@ +/* + * Copyright 2020 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 java.util.List; +import software.amazon.smithy.go.codegen.auth.AuthParameter; +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. + */ +public class SigV4AuthParameters implements GoIntegration { + private boolean isSigV4Service(Model model, ServiceShape service) { + return service.hasTrait("aws.auth#sigv4"); + } + + @Override + public List getClientPlugins() { + return ListUtils.of( + RuntimeClientPlugin.builder() + .servicePredicate(this::isSigV4Service) + .addAuthParameter(AuthParameter.REGION) + .build() + ); + } +} 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 908c87260..369a255ad 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 @@ -8,4 +8,5 @@ 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