Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ServiceIndex method to account for smithy.api#noAuth #1924

Merged
merged 1 commit into from
Aug 16, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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