-
Notifications
You must be signed in to change notification settings - Fork 218
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Add `@aws.auth#sigv4a` trait * Add `@aws.auth#sigv4a` trait Java implementation * Add `SigV4TraitsValidator` validation * Add `@aws.auth#sigv4a` trait tests * Add `@aws.auth#sigv4a` trait documentation
- Loading branch information
Steven Yuan
authored
Dec 5, 2023
1 parent
7500a94
commit c34f984
Showing
17 changed files
with
390 additions
and
8 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
90 changes: 90 additions & 0 deletions
90
smithy-aws-traits/src/main/java/software/amazon/smithy/aws/traits/auth/SigV4ATrait.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
/* | ||
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
package software.amazon.smithy.aws.traits.auth; | ||
|
||
import software.amazon.smithy.model.node.Node; | ||
import software.amazon.smithy.model.node.ObjectNode; | ||
import software.amazon.smithy.model.shapes.ShapeId; | ||
import software.amazon.smithy.model.traits.AbstractTrait; | ||
import software.amazon.smithy.model.traits.AbstractTraitBuilder; | ||
import software.amazon.smithy.model.traits.Trait; | ||
import software.amazon.smithy.utils.SmithyBuilder; | ||
import software.amazon.smithy.utils.ToSmithyBuilder; | ||
|
||
/** | ||
* Adds AWS Signature Version 4 Asymmetric authentication to a service or operation. | ||
*/ | ||
public final class SigV4ATrait extends AbstractTrait implements ToSmithyBuilder<SigV4ATrait> { | ||
public static final ShapeId ID = ShapeId.from("aws.auth#sigv4a"); | ||
private static final String NAME = "name"; | ||
|
||
private final String name; | ||
|
||
private SigV4ATrait(Builder builder) { | ||
super(ID, builder.getSourceLocation()); | ||
this.name = SmithyBuilder.requiredState(NAME, builder.name); | ||
} | ||
|
||
/** | ||
* Gets the service signing name. | ||
* | ||
* @return the service signing name | ||
*/ | ||
public String getName() { | ||
return name; | ||
} | ||
|
||
public static Builder builder() { | ||
return new Builder(); | ||
} | ||
|
||
@Override | ||
public Builder toBuilder() { | ||
return builder() | ||
.sourceLocation(getSourceLocation()) | ||
.name(getName()); | ||
} | ||
|
||
@Override | ||
protected Node createNode() { | ||
return Node.objectNodeBuilder() | ||
.sourceLocation(getSourceLocation()) | ||
.withMember(NAME, getName()) | ||
.build(); | ||
} | ||
|
||
public static final class Builder extends AbstractTraitBuilder<SigV4ATrait, Builder> { | ||
private String name; | ||
|
||
private Builder() {} | ||
|
||
@Override | ||
public SigV4ATrait build() { | ||
return new SigV4ATrait(this); | ||
} | ||
|
||
public Builder name(String name) { | ||
this.name = name; | ||
return this; | ||
} | ||
} | ||
|
||
public static final class Provider extends AbstractTrait.Provider { | ||
public Provider() { | ||
super(ID); | ||
} | ||
|
||
@Override | ||
public Trait createTrait(ShapeId target, Node value) { | ||
ObjectNode objectNode = value.expectObjectNode(); | ||
Builder builder = builder().sourceLocation(value); | ||
builder.name(objectNode.expectStringMember(NAME).getValue()); | ||
SigV4ATrait result = builder.build(); | ||
result.setNodeCache(objectNode); | ||
return result; | ||
} | ||
} | ||
} |
95 changes: 95 additions & 0 deletions
95
...aws-traits/src/main/java/software/amazon/smithy/aws/traits/auth/SigV4TraitsValidator.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
/* | ||
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
package software.amazon.smithy.aws.traits.auth; | ||
|
||
import java.util.ArrayList; | ||
import java.util.List; | ||
import java.util.Optional; | ||
import software.amazon.smithy.aws.traits.ServiceTrait; | ||
import software.amazon.smithy.model.Model; | ||
import software.amazon.smithy.model.shapes.ServiceShape; | ||
import software.amazon.smithy.model.shapes.ShapeId; | ||
import software.amazon.smithy.model.validation.AbstractValidator; | ||
import software.amazon.smithy.model.validation.ValidationEvent; | ||
import software.amazon.smithy.utils.SmithyInternalApi; | ||
|
||
/** | ||
* Validates AWS Service, SigV4, and SigV4A traits. | ||
*/ | ||
@SmithyInternalApi | ||
public final class SigV4TraitsValidator extends AbstractValidator { | ||
private static final ShapeId SERVICE_ARN_NAMESPACE = ServiceTrait.ID.withMember("arnNamespace"); | ||
private static final ShapeId SIGV4_NAME = SigV4Trait.ID.withMember("name"); | ||
private static final ShapeId SIGV4A_NAME = SigV4ATrait.ID.withMember("name"); | ||
|
||
@Override | ||
public List<ValidationEvent> validate(Model model) { | ||
List<ValidationEvent> events = new ArrayList<>(); | ||
for (ServiceShape service : model.getServiceShapes()) { | ||
events.addAll(validateService(model, service)); | ||
} | ||
return events; | ||
} | ||
|
||
/** | ||
* Validates Service and SigV4 traits. | ||
* | ||
* - service$arnNamespace, sigv4$name, and sigv4a$name SHOULD be equal. Otherwise, emits warnings. | ||
*/ | ||
private List<ValidationEvent> validateService(Model model, ServiceShape service) { | ||
List<ValidationEvent> events = new ArrayList<>(); | ||
Optional<ServiceTrait> serviceTraitOptional = service.getTrait(ServiceTrait.class); | ||
Optional<SigV4Trait> sigv4TraitOptional = service.getTrait(SigV4Trait.class); | ||
Optional<SigV4ATrait> sigv4aTraitOptional = service.getTrait(SigV4ATrait.class); | ||
if (serviceTraitOptional.isPresent()) { | ||
String serviceArnNamespace = serviceTraitOptional.get().getArnNamespace(); | ||
// Check service$arnNamespace with sigv4$name | ||
if (sigv4TraitOptional.isPresent()) { | ||
String sigv4Name = sigv4TraitOptional.get().getName(); | ||
if (!serviceArnNamespace.equals(sigv4Name)) { | ||
events.add(createValuesShouldMatchWarning( | ||
service, | ||
SERVICE_ARN_NAMESPACE, serviceArnNamespace, | ||
SIGV4_NAME, sigv4Name)); | ||
} | ||
} | ||
// Check service$arnNamespace with sigv4a$name | ||
if (sigv4aTraitOptional.isPresent()) { | ||
String sigv4aName = sigv4aTraitOptional.get().getName(); | ||
if (!serviceArnNamespace.equals(sigv4aName)) { | ||
events.add(createValuesShouldMatchWarning( | ||
service, | ||
SERVICE_ARN_NAMESPACE, serviceArnNamespace, | ||
SIGV4A_NAME, sigv4aName)); | ||
} | ||
} | ||
} | ||
// Check sigv4$name with sigv4a$name | ||
if (sigv4TraitOptional.isPresent() && sigv4aTraitOptional.isPresent()) { | ||
String sigv4Name = sigv4TraitOptional.get().getName(); | ||
String sigv4aName = sigv4aTraitOptional.get().getName(); | ||
if (!sigv4Name.equals(sigv4aName)) { | ||
events.add(createValuesShouldMatchWarning( | ||
service, | ||
SIGV4_NAME, sigv4Name, | ||
SIGV4A_NAME, sigv4aName)); | ||
} | ||
} | ||
return events; | ||
} | ||
|
||
private ValidationEvent createValuesShouldMatchWarning( | ||
ServiceShape service, | ||
ShapeId member1, | ||
String value1, | ||
ShapeId member2, | ||
String value2 | ||
) { | ||
return warning(service, String.format( | ||
"Value for `%s` \"%s\" and value for `%s` \"%s\" SHOULD match.", | ||
member1.toString(), value1, member2.toString(), value2)); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
43 changes: 43 additions & 0 deletions
43
smithy-aws-traits/src/test/java/software/amazon/smithy/aws/traits/auth/SigV4ATraitTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
/* | ||
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
package software.amazon.smithy.aws.traits.auth; | ||
|
||
import static org.hamcrest.MatcherAssert.assertThat; | ||
import static org.hamcrest.Matchers.equalTo; | ||
import static org.hamcrest.Matchers.instanceOf; | ||
import static org.junit.jupiter.api.Assertions.assertFalse; | ||
import static org.junit.jupiter.api.Assertions.assertTrue; | ||
|
||
import java.util.Optional; | ||
import org.junit.jupiter.api.Test; | ||
import software.amazon.smithy.model.node.Node; | ||
import software.amazon.smithy.model.node.ObjectNode; | ||
import software.amazon.smithy.model.node.StringNode; | ||
import software.amazon.smithy.model.shapes.ShapeId; | ||
import software.amazon.smithy.model.traits.Trait; | ||
import software.amazon.smithy.model.traits.TraitFactory; | ||
|
||
public class SigV4ATraitTest { | ||
private static final String MOCK_SIGNING_NAME = "mocksigningname"; | ||
private static final ShapeId MOCK_TARGET = ShapeId.from("ns.qux#foo"); | ||
|
||
@Test | ||
public void loadsTrait() { | ||
Node node = ObjectNode.builder() | ||
.withMember("name", StringNode.from(MOCK_SIGNING_NAME)) | ||
.build(); | ||
TraitFactory provider = TraitFactory.createServiceFactory(); | ||
Optional<Trait> trait = provider.createTrait(SigV4ATrait.ID, MOCK_TARGET, node); | ||
|
||
assertTrue(trait.isPresent()); | ||
assertThat(trait.get(), instanceOf(SigV4ATrait.class)); | ||
SigV4ATrait sigv4aTrait = (SigV4ATrait) trait.get(); | ||
assertFalse(sigv4aTrait.getName().isEmpty()); | ||
assertThat(sigv4aTrait.getName(), equalTo(MOCK_SIGNING_NAME)); | ||
assertThat(sigv4aTrait.toNode(), equalTo(node)); | ||
assertThat(sigv4aTrait.toBuilder().build(), equalTo(sigv4aTrait)); | ||
} | ||
} |
1 change: 1 addition & 0 deletions
1
...resources/software/amazon/smithy/aws/traits/errorfiles/auth/sigv4-service-mismatch.errors
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
[WARNING] smithy.example#InvalidService: Value for `aws.api#service$arnNamespace` "invalidservice" and value for `aws.auth#sigv4$name` "signingname" SHOULD match. | SigV4Traits |
12 changes: 12 additions & 0 deletions
12
...resources/software/amazon/smithy/aws/traits/errorfiles/auth/sigv4-service-mismatch.smithy
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
$version: "2.0" | ||
|
||
namespace smithy.example | ||
|
||
use aws.api#service | ||
use aws.auth#sigv4 | ||
|
||
@service(sdkId: "servicename") | ||
@sigv4(name: "signingname") | ||
service InvalidService { | ||
version: "2020-07-02" | ||
} |
1 change: 1 addition & 0 deletions
1
.../resources/software/amazon/smithy/aws/traits/errorfiles/auth/sigv4-sigv4a-mismatch.errors
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
[WARNING] smithy.example#InvalidService: Value for `aws.auth#sigv4$name` "sigv4signingname" and value for `aws.auth#sigv4a$name` "sigv4asigningname" SHOULD match. | SigV4Traits |
13 changes: 13 additions & 0 deletions
13
.../resources/software/amazon/smithy/aws/traits/errorfiles/auth/sigv4-sigv4a-mismatch.smithy
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
$version: "2.0" | ||
|
||
namespace smithy.example | ||
|
||
use aws.auth#sigv4 | ||
use aws.auth#sigv4a | ||
|
||
@auth([sigv4a, sigv4]) | ||
@sigv4(name: "sigv4signingname") | ||
@sigv4a(name: "sigv4asigningname") | ||
service InvalidService { | ||
version: "2020-07-02" | ||
} |
Oops, something went wrong.