Skip to content

Commit

Permalink
feat(codegen): support SigV4 for non AWS services
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
gosar committed May 13, 2021
1 parent c6dc029 commit 3b3ae92
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand All @@ -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-";
Expand All @@ -67,21 +68,37 @@ 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.")
.write("credentialDefaultProvider?: (input: any) => __Provider<__Credentials>;\n");
}
}

// Only one of AwsAuth or SigV4Auth should be used
// AwsAuth - for AWS services
// SigV4Auth - for non AWS services
@Override
public List<RuntimeClientPlugin> 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,
Expand All @@ -92,13 +109,31 @@ public List<RuntimeClientPlugin> 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()

);
}

Expand All @@ -114,6 +149,16 @@ public Map<String, Consumer<TypeScriptWriter>> 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 -> {
Expand Down Expand Up @@ -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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<string>;\n");
if (isAwsService(settings, model)) {
writer.writeDocs("The AWS region to which this client will send requests")
.write("region?: string | __Provider<string>;\n");
} else {
writer.writeDocs("The AWS region to use as signing region for AWS Auth")
.write("region?: string | __Provider<string>;\n");
}
}
writer.writeDocs("Value for how many times a request will be made at most in case of retry.")
.write("maxAttempts?: number | __Provider<number>;\n");
Expand Down Expand Up @@ -163,7 +168,6 @@ private Map<String, Consumer<TypeScriptWriter>> 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",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -47,7 +48,7 @@ public List<RuntimeClientPlugin> 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()
Expand Down

0 comments on commit 3b3ae92

Please sign in to comment.