Skip to content

Commit 866c75b

Browse files
committed
fix(codegen): move auth to standalone plugin
1 parent 23e48de commit 866c75b

File tree

4 files changed

+173
-82
lines changed

4 files changed

+173
-82
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
/*
2+
* Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License").
5+
* You may not use this file except in compliance with the License.
6+
* A copy of the License is located at
7+
*
8+
* http://aws.amazon.com/apache2.0
9+
*
10+
* or in the "license" file accompanying this file. This file is distributed
11+
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
12+
* express or implied. See the License for the specific language governing
13+
* permissions and limitations under the License.
14+
*/
15+
16+
package software.amazon.smithy.aws.typescript.codegen;
17+
18+
import static software.amazon.smithy.typescript.codegen.integration.RuntimeClientPlugin.Convention.HAS_CONFIG;
19+
import static software.amazon.smithy.typescript.codegen.integration.RuntimeClientPlugin.Convention.HAS_MIDDLEWARE;
20+
21+
import java.util.Collections;
22+
import java.util.List;
23+
import java.util.Map;
24+
import java.util.Set;
25+
import java.util.function.Consumer;
26+
import software.amazon.smithy.aws.traits.ServiceTrait;
27+
import software.amazon.smithy.codegen.core.SymbolProvider;
28+
import software.amazon.smithy.model.Model;
29+
import software.amazon.smithy.model.knowledge.TopDownIndex;
30+
import software.amazon.smithy.model.shapes.OperationShape;
31+
import software.amazon.smithy.model.shapes.ServiceShape;
32+
import software.amazon.smithy.model.shapes.Shape;
33+
import software.amazon.smithy.model.traits.OptionalAuthTrait;
34+
import software.amazon.smithy.typescript.codegen.LanguageTarget;
35+
import software.amazon.smithy.typescript.codegen.TypeScriptDependency;
36+
import software.amazon.smithy.typescript.codegen.TypeScriptSettings;
37+
import software.amazon.smithy.typescript.codegen.TypeScriptWriter;
38+
import software.amazon.smithy.typescript.codegen.integration.RuntimeClientPlugin;
39+
import software.amazon.smithy.typescript.codegen.integration.TypeScriptIntegration;
40+
import software.amazon.smithy.utils.ListUtils;
41+
import software.amazon.smithy.utils.MapUtils;
42+
import software.amazon.smithy.utils.SetUtils;
43+
44+
/**
45+
* Configure clients with AWS auth configurations and plugin.
46+
*/
47+
public final class AddAwsAuthPlugin implements TypeScriptIntegration {
48+
49+
@Override
50+
public byte getOrder() {
51+
// Auth plugin should resolve after region, set it to after AddBuiltinPlugins.
52+
return 10;
53+
}
54+
55+
@Override
56+
public void addConfigInterfaceFields(
57+
TypeScriptSettings settings,
58+
Model model,
59+
SymbolProvider symbolProvider,
60+
TypeScriptWriter writer
61+
) {
62+
ServiceShape service = settings.getService(model);
63+
if (!isAllOptionalAuthOperation(model, service)) {
64+
writer.addImport("Credentials", "__Credentials", TypeScriptDependency.AWS_SDK_TYPES.packageName);
65+
writer.writeDocs("Default credentials provider; Not available in browser runtime")
66+
.write("credentialDefaultProvider?: (input: any) => __Provider<__Credentials>;\n");
67+
}
68+
}
69+
70+
@Override
71+
public List<RuntimeClientPlugin> getClientPlugins() {
72+
return ListUtils.of(
73+
RuntimeClientPlugin.builder()
74+
.withConventions(AwsDependency.MIDDLEWARE_SIGNING.dependency, "AwsAuth", HAS_CONFIG)
75+
.servicePredicate((m, s) -> !isAllOptionalAuthOperation(m, s))
76+
.build(),
77+
RuntimeClientPlugin.builder()
78+
.withConventions(AwsDependency.MIDDLEWARE_SIGNING.dependency, "AwsAuth", HAS_MIDDLEWARE)
79+
// See operationUsesAwsAuth() below for AwsAuth Middleware customizations.
80+
.servicePredicate(
81+
(m, s) -> !testServiceId(s, "STS") && !hasOptionalAuthOperation(m, s)
82+
).build(),
83+
RuntimeClientPlugin.builder()
84+
.withConventions(AwsDependency.MIDDLEWARE_SIGNING.dependency, "AwsAuth", HAS_MIDDLEWARE)
85+
.operationPredicate(AddAwsAuthPlugin::operationUsesAwsAuth)
86+
.build()
87+
);
88+
}
89+
90+
@Override
91+
public Map<String, Consumer<TypeScriptWriter>> getRuntimeConfigWriters(
92+
TypeScriptSettings settings,
93+
Model model,
94+
SymbolProvider symbolProvider,
95+
LanguageTarget target
96+
) {
97+
ServiceShape service = settings.getService(model);
98+
if (isAllOptionalAuthOperation(model, service)) {
99+
return Collections.emptyMap();
100+
}
101+
switch (target) {
102+
case BROWSER:
103+
return MapUtils.of(
104+
"credentialDefaultProvider", writer -> {
105+
writer.write(
106+
"credentialDefaultProvider: (_: unknown) => () => Promise.reject(new Error("
107+
+ "\"Credential is missing\")),");
108+
}
109+
);
110+
case NODE:
111+
return MapUtils.of(
112+
"credentialDefaultProvider", writer -> {
113+
writer.addDependency(AwsDependency.CREDENTIAL_PROVIDER_NODE);
114+
writer.addImport("defaultProvider", "credentialDefaultProvider",
115+
AwsDependency.CREDENTIAL_PROVIDER_NODE.packageName);
116+
writer.write("credentialDefaultProvider,");
117+
}
118+
);
119+
default:
120+
return Collections.emptyMap();
121+
}
122+
}
123+
124+
private static boolean testServiceId(Shape serviceShape, String expectedId) {
125+
return serviceShape.getTrait(ServiceTrait.class).map(ServiceTrait::getSdkId).orElse("").equals(expectedId);
126+
}
127+
128+
private static boolean operationUsesAwsAuth(Model model, ServiceShape service, OperationShape operation) {
129+
// STS doesn't need auth for AssumeRoleWithWebIdentity, AssumeRoleWithSAML.
130+
// Remove when optionalAuth model update is published in 0533102932.
131+
if (testServiceId(service, "STS")) {
132+
Boolean isUnsignedCommand = SetUtils
133+
.of("AssumeRoleWithWebIdentity", "AssumeRoleWithSAML")
134+
.contains(operation.getId().getName());
135+
return !isUnsignedCommand;
136+
}
137+
138+
// optionalAuth trait doesn't require authentication.
139+
if (hasOptionalAuthOperation(model, service)) {
140+
return !operation.getTrait(OptionalAuthTrait.class).isPresent();
141+
}
142+
return false;
143+
}
144+
145+
private static boolean hasOptionalAuthOperation(Model model, ServiceShape service) {
146+
TopDownIndex topDownIndex = TopDownIndex.of(model);
147+
Set<OperationShape> operations = topDownIndex.getContainedOperations(service);
148+
for (OperationShape operation : operations) {
149+
if (operation.getTrait(OptionalAuthTrait.class).isPresent()) {
150+
return true;
151+
}
152+
}
153+
return false;
154+
}
155+
156+
private static boolean isAllOptionalAuthOperation(Model model, ServiceShape service) {
157+
TopDownIndex topDownIndex = TopDownIndex.of(model);
158+
Set<OperationShape> operations = topDownIndex.getContainedOperations(service);
159+
for (OperationShape operation : operations) {
160+
if (!operation.getTrait(OptionalAuthTrait.class).isPresent()) {
161+
return false;
162+
}
163+
}
164+
return true;
165+
}
166+
}

codegen/smithy-aws-typescript-codegen/src/main/java/software/amazon/smithy/aws/typescript/codegen/AddAwsRuntimeConfig.java

Lines changed: 4 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -32,16 +32,14 @@
3232
import software.amazon.smithy.utils.MapUtils;
3333

3434
/**
35-
* AWS clients need to know the service name for collecting metrics,
36-
* credentials for signing requests, and the region name used to resolve
37-
* endpoints.
35+
* AWS clients need to know the service name for collecting metrics, the
36+
* region name used to resolve endpoints, the max attempt to retry a request
37+
* and logger instance to print the log.
3838
*
3939
* <p>This plugin adds the following config interface fields:
4040
*
4141
* <ul>
4242
* <li>serviceId: Unique name to identify the service.</li>
43-
* <li>credentialDefaultProvider: Provides credentials if no credentials
44-
* are explicitly provided.</li>
4543
* <li>region: The AWS region to which this client will send requests</li>
4644
* <li>maxAttempts: Provides value for how many times a request will be
4745
* made at most in case of retry.</li>
@@ -52,8 +50,6 @@
5250
*
5351
* <ul>
5452
* <li>serviceId: Unique name to identify the service.</li>
55-
* <li>credentialDefaultProvider: Uses the default credential provider that
56-
* checks things like environment variables and the AWS config file.</li>
5753
* <li>region: Uses the default region provider that checks things like
5854
* environment variables and the AWS config file.</li>
5955
* <li>maxAttempts: Uses the default maxAttempts provider that checks things
@@ -65,9 +61,6 @@
6561
*
6662
* <ul>
6763
* <li>serviceId: Unique name to identify the service.</li>
68-
* <li>credentialDefaultProvider: Throws an exception since credentials must
69-
* be explicitly provided in the browser (environment variables and
70-
* the shared config can't be resolved from the browser).</li>
7164
* <li>region: Throws an exception since a region must
7265
* be explicitly provided in the browser (environment variables and
7366
* the shared config can't be resolved from the browser).</li>
@@ -87,13 +80,11 @@ public void addConfigInterfaceFields(
8780
TypeScriptWriter writer
8881
) {
8982
writer.addImport("Provider", "__Provider", TypeScriptDependency.AWS_SDK_TYPES.packageName);
90-
writer.addImport("Credentials", "__Credentials", TypeScriptDependency.AWS_SDK_TYPES.packageName);
83+
// writer.addImport("Credentials", "__Credentials", TypeScriptDependency.AWS_SDK_TYPES.packageName);
9184
writer.addImport("Logger", "__Logger", TypeScriptDependency.AWS_SDK_TYPES.packageName);
9285

9386
writer.writeDocs("Unique service identifier.\n@internal")
9487
.write("serviceId?: string;\n");
95-
writer.writeDocs("Default credentials provider; Not available in browser runtime")
96-
.write("credentialDefaultProvider?: (input: any) => __Provider<__Credentials>;\n");
9788
writer.writeDocs("The AWS region to which this client will send requests")
9889
.write("region?: string | __Provider<string>;\n");
9990
writer.writeDocs("Value for how many times a request will be made at most in case of retry.")
@@ -145,11 +136,6 @@ private Map<String, Consumer<TypeScriptWriter>> getDefaultConfig(LanguageTarget
145136
TypeScriptDependency.INVALID_DEPENDENCY.packageName);
146137
writer.write("region: invalidProvider(\"Region is missing\"),");
147138
},
148-
"credentialDefaultProvider", writer -> {
149-
writer.write(
150-
"credentialDefaultProvider: (_: unknown) => () => Promise.reject(new Error("
151-
+ "\"Credential is missing\")),");
152-
},
153139
"maxAttempts", writer -> {
154140
writer.addDependency(TypeScriptDependency.MIDDLEWARE_RETRY);
155141
writer.addImport("DEFAULT_MAX_ATTEMPTS", "DEFAULT_MAX_ATTEMPTS",
@@ -171,12 +157,6 @@ private Map<String, Consumer<TypeScriptWriter>> getDefaultConfig(LanguageTarget
171157
writer.write(
172158
"region: loadNodeConfig(NODE_REGION_CONFIG_OPTIONS, NODE_REGION_CONFIG_FILE_OPTIONS),");
173159
},
174-
"credentialDefaultProvider", writer -> {
175-
writer.addDependency(AwsDependency.CREDENTIAL_PROVIDER_NODE);
176-
writer.addImport("defaultProvider", "credentialDefaultProvider",
177-
AwsDependency.CREDENTIAL_PROVIDER_NODE.packageName);
178-
writer.write("credentialDefaultProvider,");
179-
},
180160
"maxAttempts", writer -> {
181161
writer.addImport("NODE_MAX_ATTEMPT_CONFIG_OPTIONS", "NODE_MAX_ATTEMPT_CONFIG_OPTIONS",
182162
TypeScriptDependency.MIDDLEWARE_RETRY.packageName);

codegen/smithy-aws-typescript-codegen/src/main/java/software/amazon/smithy/aws/typescript/codegen/AddBuiltinPlugins.java

Lines changed: 1 addition & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,8 @@
2323
import software.amazon.smithy.aws.traits.ServiceTrait;
2424
import software.amazon.smithy.model.Model;
2525
import software.amazon.smithy.model.knowledge.OperationIndex;
26-
import software.amazon.smithy.model.knowledge.TopDownIndex;
2726
import software.amazon.smithy.model.shapes.OperationShape;
28-
import software.amazon.smithy.model.shapes.ServiceShape;
2927
import software.amazon.smithy.model.shapes.Shape;
30-
import software.amazon.smithy.model.traits.OptionalAuthTrait;
3128
import software.amazon.smithy.typescript.codegen.TypeScriptDependency;
3229
import software.amazon.smithy.typescript.codegen.integration.RuntimeClientPlugin;
3330
import software.amazon.smithy.typescript.codegen.integration.TypeScriptIntegration;
@@ -51,16 +48,6 @@ public List<RuntimeClientPlugin> getClientPlugins() {
5148
RuntimeClientPlugin.builder()
5249
.withConventions(TypeScriptDependency.CONFIG_RESOLVER.dependency, "Endpoints", HAS_CONFIG)
5350
.build(),
54-
RuntimeClientPlugin.builder()
55-
.withConventions(AwsDependency.MIDDLEWARE_SIGNING.dependency, "AwsAuth", HAS_CONFIG)
56-
.servicePredicate((m, s) -> !isAllOptionalAuthOperation(m, s))
57-
.build(),
58-
RuntimeClientPlugin.builder()
59-
.withConventions(AwsDependency.MIDDLEWARE_SIGNING.dependency, "AwsAuth", HAS_MIDDLEWARE)
60-
// See operationUsesAwsAuth() below for AwsAuth Middleware customizations.
61-
.servicePredicate(
62-
(m, s) -> !testServiceId(s, "STS") && !hasOptionalAuthOperation(m, s)
63-
).build(),
6451
RuntimeClientPlugin.builder()
6552
.withConventions(TypeScriptDependency.MIDDLEWARE_RETRY.dependency, "Retry")
6653
.build(),
@@ -123,10 +110,6 @@ && testServiceId(s, "SQS"))
123110
RuntimeClientPlugin.builder()
124111
.withConventions(AwsDependency.MIDDLEWARE_HOST_HEADER.dependency, "HostHeader")
125112
.build(),
126-
RuntimeClientPlugin.builder()
127-
.withConventions(AwsDependency.MIDDLEWARE_SIGNING.dependency, "AwsAuth", HAS_MIDDLEWARE)
128-
.operationPredicate(AddBuiltinPlugins::operationUsesAwsAuth)
129-
.build(),
130113
RuntimeClientPlugin.builder()
131114
.withConventions(AwsDependency.MIDDLEWARE_LOGGER.dependency, "Logger", HAS_MIDDLEWARE)
132115
.build()
@@ -138,7 +121,7 @@ private static boolean testInputContainsMember(
138121
OperationShape operationShape,
139122
Set<String> expectedMemberNames
140123
) {
141-
OperationIndex operationIndex = model.getKnowledge(OperationIndex.class);
124+
OperationIndex operationIndex = OperationIndex.of(model);
142125
return operationIndex.getInput(operationShape)
143126
.filter(input -> input.getMemberNames().stream().anyMatch(expectedMemberNames::contains))
144127
.isPresent();
@@ -147,43 +130,4 @@ private static boolean testInputContainsMember(
147130
private static boolean testServiceId(Shape serviceShape, String expectedId) {
148131
return serviceShape.getTrait(ServiceTrait.class).map(ServiceTrait::getSdkId).orElse("").equals(expectedId);
149132
}
150-
151-
private static boolean operationUsesAwsAuth(Model model, ServiceShape service, OperationShape operation) {
152-
// STS doesn't need auth for AssumeRoleWithWebIdentity, AssumeRoleWithSAML.
153-
// Remove when optionalAuth model update is published in 0533102932.
154-
if (testServiceId(service, "STS")) {
155-
Boolean isUnsignedCommand = SetUtils
156-
.of("AssumeRoleWithWebIdentity", "AssumeRoleWithSAML")
157-
.contains(operation.getId().getName());
158-
return !isUnsignedCommand;
159-
}
160-
161-
// optionalAuth trait doesn't require authentication.
162-
if (hasOptionalAuthOperation(model, service)) {
163-
return !operation.getTrait(OptionalAuthTrait.class).isPresent();
164-
}
165-
return false;
166-
}
167-
168-
private static boolean hasOptionalAuthOperation(Model model, ServiceShape service) {
169-
TopDownIndex topDownIndex = TopDownIndex.of(model);
170-
Set<OperationShape> operations = topDownIndex.getContainedOperations(service);
171-
for (OperationShape operation : operations) {
172-
if (operation.getTrait(OptionalAuthTrait.class).isPresent()) {
173-
return true;
174-
}
175-
}
176-
return false;
177-
}
178-
179-
private static boolean isAllOptionalAuthOperation(Model model, ServiceShape service) {
180-
TopDownIndex topDownIndex = TopDownIndex.of(model);
181-
Set<OperationShape> operations = topDownIndex.getContainedOperations(service);
182-
for (OperationShape operation : operations) {
183-
if (!operation.getTrait(OptionalAuthTrait.class).isPresent()) {
184-
return false;
185-
}
186-
}
187-
return true;
188-
}
189133
}

codegen/smithy-aws-typescript-codegen/src/main/resources/META-INF/services/software.amazon.smithy.typescript.codegen.integration.TypeScriptIntegration

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,5 @@ software.amazon.smithy.aws.typescript.codegen.AddTranscribeStreamingDependency
1515
software.amazon.smithy.aws.typescript.codegen.AddUserAgentDependency
1616
software.amazon.smithy.aws.typescript.codegen.AddOmitRetryHeadersDependency
1717
software.amazon.smithy.aws.typescript.codegen.StripNewEnumNames
18-
software.amazon.smithy.aws.typescript.codegen.AddCrossRegionCopyingPlugin
18+
software.amazon.smithy.aws.typescript.codegen.AddCrossRegionCopyingPlugin
19+
software.amazon.smithy.aws.typescript.codegen.AddAwsAuthPlugin

0 commit comments

Comments
 (0)