From 3b3ae923f9f801aac4ad181dba901ff0e58cabfd Mon Sep 17 00:00:00 2001 From: Jaykumar Gosar Date: Tue, 11 May 2021 15:54:16 -0700 Subject: [PATCH] feat(codegen): support SigV4 for non AWS services Write `signingName` from the SigV4 trait for non AWS service. `region` is used for the signingRegion. A separate SigV4Auth is used for SigV4 logic for non AWS services. --- .../typescript/codegen/AddAwsAuthPlugin.java | 59 ++++++++++++++++--- .../codegen/AddAwsRuntimeConfig.java | 10 +++- .../typescript/codegen/AddBuiltinPlugins.java | 3 +- 3 files changed, 61 insertions(+), 11 deletions(-) diff --git a/codegen/smithy-aws-typescript-codegen/src/main/java/software/amazon/smithy/aws/typescript/codegen/AddAwsAuthPlugin.java b/codegen/smithy-aws-typescript-codegen/src/main/java/software/amazon/smithy/aws/typescript/codegen/AddAwsAuthPlugin.java index 2ac32aba16e4e..af4f2f0dffb1c 100644 --- a/codegen/smithy-aws-typescript-codegen/src/main/java/software/amazon/smithy/aws/typescript/codegen/AddAwsAuthPlugin.java +++ b/codegen/smithy-aws-typescript-codegen/src/main/java/software/amazon/smithy/aws/typescript/codegen/AddAwsAuthPlugin.java @@ -15,6 +15,7 @@ package software.amazon.smithy.aws.typescript.codegen; +import static software.amazon.smithy.aws.typescript.codegen.AwsTraitsUtils.isAwsService; import static software.amazon.smithy.aws.typescript.codegen.AwsTraitsUtils.isSigV4Service; import static software.amazon.smithy.typescript.codegen.integration.RuntimeClientPlugin.Convention.HAS_CONFIG; import static software.amazon.smithy.typescript.codegen.integration.RuntimeClientPlugin.Convention.HAS_MIDDLEWARE; @@ -26,6 +27,7 @@ import java.util.function.BiConsumer; import java.util.function.Consumer; import software.amazon.smithy.aws.traits.ServiceTrait; +import software.amazon.smithy.aws.traits.auth.SigV4Trait; import software.amazon.smithy.codegen.core.SymbolProvider; import software.amazon.smithy.model.Model; import software.amazon.smithy.model.knowledge.TopDownIndex; @@ -48,7 +50,6 @@ /** * Configure clients with AWS auth configurations and plugin. */ -// TODO: Think about AWS Auth supported for only some operations and not all, when not AWS service, with say @auth([]) @SmithyInternalApi public final class AddAwsAuthPlugin implements TypeScriptIntegration { static final String STS_CLIENT_PREFIX = "sts-client-"; @@ -67,6 +68,12 @@ public void addConfigInterfaceFields( if (!isSigV4Service(service)) { return; } + + if (!isAwsService(service)) { + writer.writeDocs("The service name to use as the signing service for AWS Auth\n@internal") + .write("signingName?: string;\n"); + } + if (!areAllOptionalAuthOperations(model, service)) { writer.addImport("Credentials", "__Credentials", TypeScriptDependency.AWS_SDK_TYPES.packageName); writer.writeDocs("Default credentials provider; Not available in browser runtime.") @@ -74,14 +81,24 @@ public void addConfigInterfaceFields( } } + // Only one of AwsAuth or SigV4Auth should be used + // AwsAuth - for AWS services + // SigV4Auth - for non AWS services @Override public List getClientPlugins() { return ListUtils.of( RuntimeClientPlugin.builder() .withConventions(AwsDependency.MIDDLEWARE_SIGNING.dependency, "AwsAuth", HAS_CONFIG) .servicePredicate((m, s) -> isSigV4Service(s) - && !areAllOptionalAuthOperations(m, s) - && !testServiceId(s, "STS")) + && isAwsService(s) + && !testServiceId(s, "STS") + && !areAllOptionalAuthOperations(m, s)) + .build(), + RuntimeClientPlugin.builder() + .withConventions(AwsDependency.MIDDLEWARE_SIGNING.dependency, "SigV4Auth", HAS_CONFIG) + .servicePredicate((m, s) -> isSigV4Service(s) + && !isAwsService(s) + && !areAllOptionalAuthOperations(m, s)) .build(), RuntimeClientPlugin.builder() .withConventions(AwsDependency.STS_MIDDLEWARE.dependency, @@ -92,13 +109,31 @@ public List getClientPlugins() { RuntimeClientPlugin.builder() .withConventions(AwsDependency.MIDDLEWARE_SIGNING.dependency, "AwsAuth", HAS_MIDDLEWARE) // See operationUsesAwsAuth() below for AwsAuth Middleware customizations. - .servicePredicate( - (m, s) -> !testServiceId(s, "STS") && isSigV4Service(s) && !hasOptionalAuthOperation(m, s) + .servicePredicate((m, s) -> isSigV4Service(s) + && isAwsService(s) + && !testServiceId(s, "STS") + && !hasOptionalAuthOperation(m, s) + ).build(), + RuntimeClientPlugin.builder() + .withConventions(AwsDependency.MIDDLEWARE_SIGNING.dependency, "SigV4Auth", HAS_MIDDLEWARE) + // See operationUsesAwsAuth() below for AwsAuth Middleware customizations. + .servicePredicate((m, s) -> isSigV4Service(s) + && !isAwsService(s) + && !hasOptionalAuthOperation(m, s) ).build(), RuntimeClientPlugin.builder() .withConventions(AwsDependency.MIDDLEWARE_SIGNING.dependency, "AwsAuth", HAS_MIDDLEWARE) - .operationPredicate(AddAwsAuthPlugin::operationUsesAwsAuth) + .operationPredicate((m, s, o) -> isSigV4Service(s) + && isAwsService(s) + && operationUsesAwsAuth(m, s, o)) + .build(), + RuntimeClientPlugin.builder() + .withConventions(AwsDependency.MIDDLEWARE_SIGNING.dependency, "SigV4Auth", HAS_MIDDLEWARE) + .operationPredicate((m, s, o) -> isSigV4Service(s) + && !isAwsService(s) + && operationUsesAwsAuth(m, s, o)) .build() + ); } @@ -114,6 +149,16 @@ public Map> getRuntimeConfigWriters( return Collections.emptyMap(); } switch (target) { + case SHARED: + if (isAwsService(service)) { + return Collections.emptyMap(); + } + String signingService = service.getTrait(SigV4Trait.class).get().getName(); + return MapUtils.of( + "signingName", writer -> { + writer.write("signingName: $S,", signingService); + } + ); case BROWSER: return MapUtils.of( "credentialDefaultProvider", writer -> { @@ -208,7 +253,7 @@ private static boolean operationUsesAwsAuth(Model model, ServiceShape service, O } // optionalAuth trait doesn't require authentication. - if (isSigV4Service(service) && hasOptionalAuthOperation(model, service)) { + if (hasOptionalAuthOperation(model, service)) { return !operation.hasTrait(OptionalAuthTrait.class); } return false; diff --git a/codegen/smithy-aws-typescript-codegen/src/main/java/software/amazon/smithy/aws/typescript/codegen/AddAwsRuntimeConfig.java b/codegen/smithy-aws-typescript-codegen/src/main/java/software/amazon/smithy/aws/typescript/codegen/AddAwsRuntimeConfig.java index 75e4c61b0c138..71ffc8470c415 100644 --- a/codegen/smithy-aws-typescript-codegen/src/main/java/software/amazon/smithy/aws/typescript/codegen/AddAwsRuntimeConfig.java +++ b/codegen/smithy-aws-typescript-codegen/src/main/java/software/amazon/smithy/aws/typescript/codegen/AddAwsRuntimeConfig.java @@ -95,8 +95,13 @@ public void addConfigInterfaceFields( .write("serviceId?: string;\n"); } if (isSigV4Service(settings, model)) { - writer.writeDocs("The AWS region to which this client will send requests or use as signingRegion") - .write("region?: string | __Provider;\n"); + if (isAwsService(settings, model)) { + writer.writeDocs("The AWS region to which this client will send requests") + .write("region?: string | __Provider;\n"); + } else { + writer.writeDocs("The AWS region to use as signing region for AWS Auth") + .write("region?: string | __Provider;\n"); + } } writer.writeDocs("Value for how many times a request will be made at most in case of retry.") .write("maxAttempts?: number | __Provider;\n"); @@ -163,7 +168,6 @@ private Map> getDefaultConfig( return defaultConfigs; case NODE: if (isSigV4Service) { - // TODO: For non-AWS service, figure out how the region should be configured. defaultConfigs.put("region", writer -> { writer.addDependency(AwsDependency.NODE_CONFIG_PROVIDER); writer.addImport("loadConfig", "loadNodeConfig", diff --git a/codegen/smithy-aws-typescript-codegen/src/main/java/software/amazon/smithy/aws/typescript/codegen/AddBuiltinPlugins.java b/codegen/smithy-aws-typescript-codegen/src/main/java/software/amazon/smithy/aws/typescript/codegen/AddBuiltinPlugins.java index d23a00be70413..df7decfbf530d 100644 --- a/codegen/smithy-aws-typescript-codegen/src/main/java/software/amazon/smithy/aws/typescript/codegen/AddBuiltinPlugins.java +++ b/codegen/smithy-aws-typescript-codegen/src/main/java/software/amazon/smithy/aws/typescript/codegen/AddBuiltinPlugins.java @@ -16,6 +16,7 @@ package software.amazon.smithy.aws.typescript.codegen; import static software.amazon.smithy.aws.typescript.codegen.AwsTraitsUtils.isAwsService; +import static software.amazon.smithy.aws.typescript.codegen.AwsTraitsUtils.isSigV4Service; import static software.amazon.smithy.typescript.codegen.integration.RuntimeClientPlugin.Convention.HAS_CONFIG; import static software.amazon.smithy.typescript.codegen.integration.RuntimeClientPlugin.Convention.HAS_MIDDLEWARE; @@ -47,7 +48,7 @@ public List getClientPlugins() { return ListUtils.of( RuntimeClientPlugin.builder() .withConventions(TypeScriptDependency.CONFIG_RESOLVER.dependency, "Region", HAS_CONFIG) - .servicePredicate((m, s) -> isAwsService(s)) + .servicePredicate((m, s) -> isSigV4Service(s)) .build(), // Only one of Endpoints or CustomEndpoints should be used RuntimeClientPlugin.builder()