Skip to content

Commit

Permalink
Add ServiceIndex method to account for smithy.api#noAuth
Browse files Browse the repository at this point in the history
Use AuthSchemeMode enum
  • Loading branch information
gosar committed Aug 16, 2023
1 parent 0ce4187 commit 0bc6bf2
Show file tree
Hide file tree
Showing 4 changed files with 342 additions and 57 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,11 @@
import software.amazon.smithy.model.shapes.ToShapeId;
import software.amazon.smithy.model.traits.AuthDefinitionTrait;
import software.amazon.smithy.model.traits.AuthTrait;
import software.amazon.smithy.model.traits.OptionalAuthTrait;
import software.amazon.smithy.model.traits.ProtocolDefinitionTrait;
import software.amazon.smithy.model.traits.Trait;
import software.amazon.smithy.model.traits.synthetic.NoAuthTrait;
import software.amazon.smithy.utils.MapUtils;

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

/**
* Defines the type of auth schemes returned by {@link #getEffectiveAuthSchemes}.
*/
public enum AuthSchemeMode {

/**
* Use only the modeled auth schemes. This is the default.
*/
MODELED,

/**
* Use the modeled auth schemes, as well as the synthetic {@link NoAuthTrait} where applicable.
*
* <p>The Smithy Reference Architecture recommends using the {@code smithy.api#noAuth} auth scheme to represent
* no authentication which is available as the {@link NoAuthTrait}.
*/
NO_AUTH_AWARE;
}

/**
* Get all protocol traits attached to a service.
*
Expand Down Expand Up @@ -154,6 +176,30 @@ public Map<ShapeId, Trait> getEffectiveAuthSchemes(ToShapeId service) {
.orElse(Collections.emptyMap());
}

/**
* Gets a list of effective authentication schemes applied to a service, based on the AuthSchemeMode.
*
* <p>If AuthSchemeMode is {@code MODELED}, which is the default, the behavior is same as
* {@link #getEffectiveAuthSchemes(ToShapeId)}.
*
* <p>If AuthSchemeMode is {@code NO_AUTH_AWARE}, the behavior is same, except that if the service has no effective
* auth schemes, instead of an empty map, it returns the {@code smithy.api#noAuth} auth scheme. It avoids having to
* special case handling an empty result. The returned map will always contain at least 1 entry.
*
* @param service Service to get the effective authentication schemes of.
* @param authSchemeMode AuthSchemeMode to determine which authentication schemes to include.
* @return Returns a map of the trait shape ID to the auth trait itself.
*/
public Map<ShapeId, Trait> getEffectiveAuthSchemes(ToShapeId service, AuthSchemeMode authSchemeMode) {
Map<ShapeId, Trait> authSchemes = getEffectiveAuthSchemes(service);
if (authSchemeMode == AuthSchemeMode.NO_AUTH_AWARE) {
if (authSchemes.isEmpty()) {
authSchemes = MapUtils.of(NoAuthTrait.ID, new NoAuthTrait());
}
}
return authSchemes;
}

/**
* Gets a list of effective authentication schemes applied to an operation
* bound within a service.
Expand Down Expand Up @@ -198,7 +244,49 @@ public Map<ShapeId, Trait> getEffectiveAuthSchemes(ToShapeId service, ToShapeId
.orElse(Collections.emptyMap());
}

private Map<ShapeId, Trait> getAuthTraitValues(Shape service, Shape subject) {
/**
* Gets a list of effective authentication schemes applied to an operation
* bound within a service, based on the AuthSchemeMode.
*
* <p>If AuthSchemeMode is {@code MODELED}, which is the default, the behavior is same as
* {@link #getEffectiveAuthSchemes(ToShapeId, ToShapeId)}.
*
* <p>If AuthSchemeMode is {@code NO_AUTH_AWARE}, the behavior is same, with the following differences:
* If the operation has no effective auth schemes, instead of an empty map, it returns the {@code smithy.api#noAuth}
* auth scheme.
* If the operation has the {@code smithy.api#optionalAuth} trait, it adds {@code smithy.api#noAuth} to the end.
*
* <p>Using {@code NO_AUTH_AWARE} accounts for {@code smithy.api#optionalAuth} and avoids having to special case
* handling an empty result. The returned map will always contain at least 1 entry.
*
* <p>The {@code smithy.api#noAuth} scheme, if present, is always the last scheme.
*
* @param service Service the operation is within.
* @param operation Operation to get the effective authentication schemes of.
* @param authSchemeMode AuthSchemeMode to determine which authentication schemes to include.
* @return Returns a map of the trait shape ID to the auth trait itself.
*/
public Map<ShapeId, Trait> getEffectiveAuthSchemes(ToShapeId service,
ToShapeId operation,
AuthSchemeMode authSchemeMode) {
Map<ShapeId, Trait> authSchemes = getEffectiveAuthSchemes(service, operation);
if (authSchemeMode == AuthSchemeMode.NO_AUTH_AWARE) {
if (authSchemes.isEmpty() || hasOptionalAuth(operation)) {
authSchemes = new LinkedHashMap<>(authSchemes);
authSchemes.put(NoAuthTrait.ID, new NoAuthTrait());
}
}
return authSchemes;
}

private boolean hasOptionalAuth(ToShapeId operation) {
return getModel()
.getShape(operation.toShapeId())
.filter(shape -> shape.hasTrait(OptionalAuthTrait.class))
.isPresent();
}

private static Map<ShapeId, Trait> getAuthTraitValues(Shape service, Shape subject) {
if (!subject.hasTrait(AuthTrait.class)) {
return null;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/*
* Copyright 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.model.traits.synthetic;

import software.amazon.smithy.model.knowledge.ServiceIndex;
import software.amazon.smithy.model.knowledge.ServiceIndex.AuthSchemeMode;
import software.amazon.smithy.model.node.Node;
import software.amazon.smithy.model.shapes.ShapeId;
import software.amazon.smithy.model.traits.AnnotationTrait;

/**
* An auth scheme trait for {@code smithy.api#noAuth} which indicates no authentication. This is not a real trait
* in the semantic model, but a valid auth scheme for use in {@link ServiceIndex#getEffectiveAuthSchemes} with
* {@link AuthSchemeMode#NO_AUTH_AWARE}.
*/
public final class NoAuthTrait extends AnnotationTrait {

public static final ShapeId ID = ShapeId.from("smithy.api#noAuth");

public NoAuthTrait() {
super(ID, Node.objectNode());
}

@Override
public boolean isSynthetic() {
return true;
}
}
Loading

0 comments on commit 0bc6bf2

Please sign in to comment.