-
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.
This commit introduces the iamAction trait to both consolidate and enhance the customization for IAM actions in derived from Smithy operations. It deprecates the actionName, actionPermissionDescription, and requiredAction traits - placing their behavior in the name, documentation, and requiredAction members respectively. A relativeDocumentation member is new, allowing for linking to docs within IAM documentation. A createsResources member is new, allowing for the explicit listing of resources that performing an IAM action will create. A resources member is new, allowing for the override configuration of required and optional resources that an IAM action can be authorized against (including the condition keys that can be used). This enables the detachment of an IAM action from being required to authorize against its resource hierarchy for special cases. The specification is also reorganized into sections for traits affecting resources, actions, and condition keys for easier navigation.
- Loading branch information
Showing
17 changed files
with
1,159 additions
and
240 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
112 changes: 112 additions & 0 deletions
112
...hy-aws-iam-traits/src/main/java/software/amazon/smithy/aws/iam/traits/ActionResource.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,112 @@ | ||
/* | ||
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
package software.amazon.smithy.aws.iam.traits; | ||
|
||
import java.util.Collections; | ||
import java.util.List; | ||
import java.util.Objects; | ||
import software.amazon.smithy.model.node.ArrayNode; | ||
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.node.ToNode; | ||
import software.amazon.smithy.utils.BuilderRef; | ||
import software.amazon.smithy.utils.SmithyBuilder; | ||
import software.amazon.smithy.utils.ToSmithyBuilder; | ||
|
||
/** | ||
* Contains information about a resource an IAM action can be authorized against. | ||
*/ | ||
public final class ActionResource implements ToNode, ToSmithyBuilder<ActionResource> { | ||
private static final String CONDITION_KEYS = "conditionKeys"; | ||
|
||
private final List<String> conditionKeys; | ||
|
||
private ActionResource(Builder builder) { | ||
this.conditionKeys = builder.conditionKeys.copy(); | ||
} | ||
|
||
/** | ||
* Gets the condition keys used for authorizing against this resource. | ||
* | ||
* @return the condition keys. | ||
*/ | ||
public List<String> getConditionKeys() { | ||
return conditionKeys; | ||
} | ||
|
||
public static Builder builder() { | ||
return new Builder(); | ||
} | ||
|
||
public static ActionResource fromNode(Node value) { | ||
Builder builder = builder(); | ||
value.expectObjectNode() | ||
.warnIfAdditionalProperties(Collections.singletonList(CONDITION_KEYS)) | ||
.getArrayMember(CONDITION_KEYS, StringNode::getValue, builder::conditionKeys); | ||
return builder.build(); | ||
} | ||
|
||
@Override | ||
public Node toNode() { | ||
ObjectNode.Builder builder = Node.objectNodeBuilder(); | ||
if (!conditionKeys.isEmpty()) { | ||
builder.withMember(CONDITION_KEYS, ArrayNode.fromStrings(conditionKeys)); | ||
} | ||
return builder.build(); | ||
} | ||
|
||
@Override | ||
public SmithyBuilder<ActionResource> toBuilder() { | ||
return builder().conditionKeys(conditionKeys); | ||
} | ||
|
||
@Override | ||
public boolean equals(Object o) { | ||
if (this == o) { | ||
return true; | ||
} else if (o == null || getClass() != o.getClass()) { | ||
return false; | ||
} | ||
ActionResource that = (ActionResource) o; | ||
return Objects.equals(conditionKeys, that.conditionKeys); | ||
} | ||
|
||
@Override | ||
public int hashCode() { | ||
return Objects.hash(conditionKeys); | ||
} | ||
|
||
public static final class Builder implements SmithyBuilder<ActionResource> { | ||
private final BuilderRef<List<String>> conditionKeys = BuilderRef.forList(); | ||
|
||
@Override | ||
public ActionResource build() { | ||
return new ActionResource(this); | ||
} | ||
|
||
public Builder conditionKeys(List<String> conditionKeys) { | ||
clearConditionKeys(); | ||
this.conditionKeys.get().addAll(conditionKeys); | ||
return this; | ||
} | ||
|
||
public Builder clearConditionKeys() { | ||
conditionKeys.get().clear(); | ||
return this; | ||
} | ||
|
||
public Builder addConditionKey(String conditionKey) { | ||
conditionKeys.get().add(conditionKey); | ||
return this; | ||
} | ||
|
||
public Builder removeConditionKey(String conditionKey) { | ||
conditionKeys.get().remove(conditionKey); | ||
return this; | ||
} | ||
} | ||
} |
165 changes: 165 additions & 0 deletions
165
...y-aws-iam-traits/src/main/java/software/amazon/smithy/aws/iam/traits/ActionResources.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,165 @@ | ||
/* | ||
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
package software.amazon.smithy.aws.iam.traits; | ||
|
||
import java.util.Map; | ||
import java.util.Objects; | ||
import software.amazon.smithy.model.node.Node; | ||
import software.amazon.smithy.model.node.ObjectNode; | ||
import software.amazon.smithy.model.node.ToNode; | ||
import software.amazon.smithy.utils.BuilderRef; | ||
import software.amazon.smithy.utils.ListUtils; | ||
import software.amazon.smithy.utils.SmithyBuilder; | ||
import software.amazon.smithy.utils.ToSmithyBuilder; | ||
|
||
/** | ||
* Contains information about the resources an IAM action can be authorized against. | ||
*/ | ||
public final class ActionResources implements ToNode, ToSmithyBuilder<ActionResources> { | ||
private static final String REQUIRED = "required"; | ||
private static final String OPTIONAL = "optional"; | ||
|
||
private final Map<String, ActionResource> required; | ||
private final Map<String, ActionResource> optional; | ||
|
||
private ActionResources(Builder builder) { | ||
required = builder.required.copy(); | ||
optional = builder.optional.copy(); | ||
} | ||
|
||
/** | ||
* Gets the resources that will always be authorized against for | ||
* functionality of the IAM action. | ||
* | ||
* @return the required resources. | ||
*/ | ||
public Map<String, ActionResource> getRequired() { | ||
return required; | ||
} | ||
|
||
/** | ||
* Gets the resources that will be authorized against based on | ||
* optional behavior of the IAM action. | ||
* | ||
* @return the optional resources. | ||
*/ | ||
public Map<String, ActionResource> getOptional() { | ||
return optional; | ||
} | ||
|
||
private static Builder builder() { | ||
return new Builder(); | ||
} | ||
|
||
public static ActionResources fromNode(Node value) { | ||
Builder builder = builder(); | ||
ObjectNode node = value.expectObjectNode() | ||
.warnIfAdditionalProperties(ListUtils.of(REQUIRED, OPTIONAL)); | ||
if (node.containsMember(REQUIRED)) { | ||
for (Map.Entry<String, Node> entry : node.expectObjectMember(REQUIRED).getStringMap().entrySet()) { | ||
builder.putRequired(entry.getKey(), ActionResource.fromNode(entry.getValue())); | ||
} | ||
} | ||
if (node.containsMember(OPTIONAL)) { | ||
for (Map.Entry<String, Node> entry : node.expectObjectMember(OPTIONAL).getStringMap().entrySet()) { | ||
builder.putOptional(entry.getKey(), ActionResource.fromNode(entry.getValue())); | ||
} | ||
} | ||
return builder.build(); | ||
} | ||
|
||
@Override | ||
public Node toNode() { | ||
ObjectNode.Builder builder = Node.objectNodeBuilder(); | ||
if (!required.isEmpty()) { | ||
ObjectNode.Builder requiredBuilder = Node.objectNodeBuilder(); | ||
for (Map.Entry<String, ActionResource> requiredEntry : required.entrySet()) { | ||
requiredBuilder.withMember(requiredEntry.getKey(), requiredEntry.getValue().toNode()); | ||
} | ||
} | ||
if (!optional.isEmpty()) { | ||
ObjectNode.Builder optionalBuilder = Node.objectNodeBuilder(); | ||
for (Map.Entry<String, ActionResource> optionalEntry : optional.entrySet()) { | ||
optionalBuilder.withMember(optionalEntry.getKey(), optionalEntry.getValue().toNode()); | ||
} | ||
} | ||
return builder.build(); | ||
} | ||
|
||
@Override | ||
public SmithyBuilder<ActionResources> toBuilder() { | ||
return builder().required(required).optional(optional); | ||
} | ||
|
||
@Override | ||
public boolean equals(Object o) { | ||
if (this == o) { | ||
return true; | ||
} else if (o == null || getClass() != o.getClass()) { | ||
return false; | ||
} | ||
ActionResources that = (ActionResources) o; | ||
return Objects.equals(required, that.required) | ||
&& Objects.equals(optional, that.optional); | ||
} | ||
|
||
@Override | ||
public int hashCode() { | ||
return Objects.hash(required, optional); | ||
} | ||
|
||
public static final class Builder implements SmithyBuilder<ActionResources> { | ||
private final BuilderRef<Map<String, ActionResource>> required = BuilderRef.forOrderedMap(); | ||
private final BuilderRef<Map<String, ActionResource>> optional = BuilderRef.forOrderedMap(); | ||
|
||
@Override | ||
public ActionResources build() { | ||
return new ActionResources(this); | ||
} | ||
|
||
public Builder clearRequired() { | ||
required.get().clear(); | ||
return this; | ||
} | ||
|
||
public Builder required(Map<String, ActionResource> required) { | ||
clearRequired(); | ||
this.required.get().putAll(required); | ||
return this; | ||
} | ||
|
||
public Builder putRequired(String resourceName, ActionResource actionResource) { | ||
required.get().put(resourceName, actionResource); | ||
return this; | ||
} | ||
|
||
public Builder removeRequired(String resourceName) { | ||
required.get().remove(resourceName); | ||
return this; | ||
} | ||
|
||
public Builder clearOptional() { | ||
optional.get().clear(); | ||
return this; | ||
} | ||
|
||
public Builder optional(Map<String, ActionResource> optional) { | ||
clearOptional(); | ||
this.optional.get().putAll(optional); | ||
return this; | ||
} | ||
|
||
public Builder putOptional(String resourceName, ActionResource actionResource) { | ||
optional.get().put(resourceName, actionResource); | ||
return this; | ||
} | ||
|
||
public Builder removeOptional(String resourceName) { | ||
optional.get().remove(resourceName); | ||
return this; | ||
} | ||
} | ||
} |
Oops, something went wrong.