Skip to content

Commit 795ee39

Browse files
committed
Add ServiceIndex method to account for smithy.api#noAuth
Use AuthSchemeMode enum
1 parent 8635932 commit 795ee39

File tree

4 files changed

+342
-57
lines changed

4 files changed

+342
-57
lines changed

smithy-model/src/main/java/software/amazon/smithy/model/knowledge/ServiceIndex.java

+89-1
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,11 @@
2929
import software.amazon.smithy.model.shapes.ToShapeId;
3030
import software.amazon.smithy.model.traits.AuthDefinitionTrait;
3131
import software.amazon.smithy.model.traits.AuthTrait;
32+
import software.amazon.smithy.model.traits.OptionalAuthTrait;
3233
import software.amazon.smithy.model.traits.ProtocolDefinitionTrait;
3334
import software.amazon.smithy.model.traits.Trait;
35+
import software.amazon.smithy.model.traits.synthetic.NoAuthTrait;
36+
import software.amazon.smithy.utils.MapUtils;
3437

3538
/**
3639
* An index that resolves service protocols and auth schemes.
@@ -63,6 +66,25 @@ public static ServiceIndex of(Model model) {
6366
return model.getKnowledge(ServiceIndex.class, ServiceIndex::new);
6467
}
6568

69+
/**
70+
* Defines the type of auth schemes returned by {@link #getEffectiveAuthSchemes}.
71+
*/
72+
public enum AuthSchemeMode {
73+
74+
/**
75+
* Use only the modeled auth schemes. This is the default.
76+
*/
77+
MODELED,
78+
79+
/**
80+
* Use the modeled auth schemes, as well as the synthetic {@link NoAuthTrait} where applicable.
81+
*
82+
* <p>The Smithy Reference Architecture recommends using the {@code smithy.api#noAuth} auth scheme to represent
83+
* no authentication which is available as the {@link NoAuthTrait}.
84+
*/
85+
NO_AUTH_AWARE;
86+
}
87+
6688
/**
6789
* Get all protocol traits attached to a service.
6890
*
@@ -154,6 +176,30 @@ public Map<ShapeId, Trait> getEffectiveAuthSchemes(ToShapeId service) {
154176
.orElse(Collections.emptyMap());
155177
}
156178

179+
/**
180+
* Gets a list of effective authentication schemes applied to a service, based on the AuthSchemeMode.
181+
*
182+
* <p>If AuthSchemeMode is {@code MODELED}, which is the default, the behavior is same as
183+
* {@link #getEffectiveAuthSchemes(ToShapeId)}.
184+
*
185+
* <p>If AuthSchemeMode is {@code NO_AUTH_AWARE}, the behavior is same, except that if the service has no effective
186+
* auth schemes, instead of an empty map, it returns the {@code smithy.api#noAuth} auth scheme. It avoids having to
187+
* special case handling an empty result. The returned map will always contain at least 1 entry.
188+
*
189+
* @param service Service to get the effective authentication schemes of.
190+
* @param authSchemeMode AuthSchemeMode to determine which authentication schemes to include.
191+
* @return Returns a map of the trait shape ID to the auth trait itself.
192+
*/
193+
public Map<ShapeId, Trait> getEffectiveAuthSchemes(ToShapeId service, AuthSchemeMode authSchemeMode) {
194+
Map<ShapeId, Trait> authSchemes = getEffectiveAuthSchemes(service);
195+
if (authSchemeMode == AuthSchemeMode.NO_AUTH_AWARE) {
196+
if (authSchemes.isEmpty()) {
197+
authSchemes = MapUtils.of(NoAuthTrait.ID, new NoAuthTrait());
198+
}
199+
}
200+
return authSchemes;
201+
}
202+
157203
/**
158204
* Gets a list of effective authentication schemes applied to an operation
159205
* bound within a service.
@@ -198,7 +244,49 @@ public Map<ShapeId, Trait> getEffectiveAuthSchemes(ToShapeId service, ToShapeId
198244
.orElse(Collections.emptyMap());
199245
}
200246

201-
private Map<ShapeId, Trait> getAuthTraitValues(Shape service, Shape subject) {
247+
/**
248+
* Gets a list of effective authentication schemes applied to an operation
249+
* bound within a service, based on the AuthSchemeMode.
250+
*
251+
* <p>If AuthSchemeMode is {@code MODELED}, which is the default, the behavior is same as
252+
* {@link #getEffectiveAuthSchemes(ToShapeId, ToShapeId)}.
253+
*
254+
* <p>If AuthSchemeMode is {@code NO_AUTH_AWARE}, the behavior is same, with the following differences:
255+
* If the operation has no effective auth schemes, instead of an empty map, it returns the {@code smithy.api#noAuth}
256+
* auth scheme.
257+
* If the operation has the {@code smithy.api#optionalAuth} trait, it adds {@code smithy.api#noAuth} to the end.
258+
*
259+
* <p>Using {@code NO_AUTH_AWARE} accounts for {@code smithy.api#optionalAuth} and avoids having to special case
260+
* handling an empty result. The returned map will always contain at least 1 entry.
261+
*
262+
* <p>The {@code smithy.api#noAuth} scheme, if present, is always the last scheme.
263+
*
264+
* @param service Service the operation is within.
265+
* @param operation Operation to get the effective authentication schemes of.
266+
* @param authSchemeMode AuthSchemeMode to determine which authentication schemes to include.
267+
* @return Returns a map of the trait shape ID to the auth trait itself.
268+
*/
269+
public Map<ShapeId, Trait> getEffectiveAuthSchemes(ToShapeId service,
270+
ToShapeId operation,
271+
AuthSchemeMode authSchemeMode) {
272+
Map<ShapeId, Trait> authSchemes = getEffectiveAuthSchemes(service, operation);
273+
if (authSchemeMode == AuthSchemeMode.NO_AUTH_AWARE) {
274+
if (authSchemes.isEmpty() || hasOptionalAuth(operation)) {
275+
authSchemes = new LinkedHashMap<>(authSchemes);
276+
authSchemes.put(NoAuthTrait.ID, new NoAuthTrait());
277+
}
278+
}
279+
return authSchemes;
280+
}
281+
282+
private boolean hasOptionalAuth(ToShapeId operation) {
283+
return getModel()
284+
.getShape(operation.toShapeId())
285+
.filter(shape -> shape.hasTrait(OptionalAuthTrait.class))
286+
.isPresent();
287+
}
288+
289+
private static Map<ShapeId, Trait> getAuthTraitValues(Shape service, Shape subject) {
202290
if (!subject.hasTrait(AuthTrait.class)) {
203291
return null;
204292
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/*
2+
* Copyright 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.model.traits.synthetic;
17+
18+
import software.amazon.smithy.model.knowledge.ServiceIndex;
19+
import software.amazon.smithy.model.knowledge.ServiceIndex.AuthSchemeMode;
20+
import software.amazon.smithy.model.node.Node;
21+
import software.amazon.smithy.model.shapes.ShapeId;
22+
import software.amazon.smithy.model.traits.AnnotationTrait;
23+
24+
/**
25+
* An auth scheme trait for {@code smithy.api#noAuth} which indicates no authentication. This is not a real trait
26+
* in the semantic model, but a valid auth scheme for use in {@link ServiceIndex#getEffectiveAuthSchemes} with
27+
* {@link AuthSchemeMode#NO_AUTH_AWARE}.
28+
*/
29+
public final class NoAuthTrait extends AnnotationTrait {
30+
31+
public static final ShapeId ID = ShapeId.from("smithy.api#noAuth");
32+
33+
public NoAuthTrait() {
34+
super(ID, Node.objectNode());
35+
}
36+
37+
@Override
38+
public boolean isSynthetic() {
39+
return true;
40+
}
41+
}

0 commit comments

Comments
 (0)