diff --git a/.doc_gen/metadata/iam_metadata.yaml b/.doc_gen/metadata/iam_metadata.yaml
index 1a50e216dbf..883bec651de 100644
--- a/.doc_gen/metadata/iam_metadata.yaml
+++ b/.doc_gen/metadata/iam_metadata.yaml
@@ -3523,3 +3523,40 @@ iam_Scenario_CreateUserAssumeRole:
iam: {CreateUser, CreateAccessKey, CreateRole, CreatePolicy, AttachRolePolicy,
PutUserPolicy, DeleteUserPolicy, DetachRolePolicy, DeletePolicy, DeleteRole,
DeleteAccessKey, DeleteUser}
+iam_Scenario_IamPolicyBuilder:
+ title: Work with the &IAM; Policy Builder API using an &AWS; SDK
+ title_abbrev: Work with the &IAM; Policy Builder API
+ synopsis_list:
+ - Create &IAM; policies by using the object-oriented API.
+ - Use the &IAM; Policy Builder API with the &IAM; service.
+ category: Scenarios
+ languages:
+ Java:
+ versions:
+ - sdk_version: 2
+ github: javav2/example_code/iam
+ sdkguide: sdk-for-java/latest/developer-guide/feature-iam-policy-builder.html
+ excerpts:
+ - description: The examples use the following imports.
+ snippet_tags:
+ - iam.java2.policy_builder.policy_builder_examples.imports
+ - description: Create a time-based policy.
+ snippet_tags:
+ - iam.java2.policy_builder.time_based
+ - description: Create a policy with multiple conditions.
+ snippet_tags:
+ - iam.java2.policy_builder.multiple_conditions
+ - description: Use principals in a policy.
+ snippet_tags:
+ - iam.java2.policy_builder.specify_principals
+ - description: Allow cross-account access.
+ snippet_tags:
+ - iam.java2.policy_builder.allow_cross_account_access
+ - description: Build and upload an IamPolicy
.
+ snippet_tags:
+ - iam.java2.policy_builder.create_and_upload_policy
+ - description: Download and work with an IamPolicy
.
+ snippet_tags:
+ - iam.java2.policy_builder.create_new_based_on_existing_policy
+ services:
+ iam: {CreatePolicy, GetPolicy, GetPolicyVersion}
diff --git a/javav2/example_code/iam/Readme.md b/javav2/example_code/iam/Readme.md
index e1561d11c31..e71bfb9a421 100644
--- a/javav2/example_code/iam/Readme.md
+++ b/javav2/example_code/iam/Readme.md
@@ -56,7 +56,8 @@ Code excerpts that show you how to call individual service functions.
Code examples that show you how to accomplish a specific task by calling multiple
functions within the same service.
-* [Create a user and assume a role](src/main/java/com/example/iam/IAMScenario.java)
+* [Create a user and assume a role](src/main/java/com/example/iam/IAMScenario.java)
+* [Work with the IAM Policy Builder API](src/main/java/com/example/iam/IamPolicyBuilderExamples.java)
## Run the examples
diff --git a/javav2/example_code/iam/pom.xml b/javav2/example_code/iam/pom.xml
index eb23a6ea66b..ce39b5f3b01 100644
--- a/javav2/example_code/iam/pom.xml
+++ b/javav2/example_code/iam/pom.xml
@@ -7,8 +7,9 @@
IAMJ2Project
1.0-SNAPSHOT
- 1.8
- 1.8
+ 11
+ 11
+ 1.7.28
@@ -27,7 +28,14 @@
software.amazon.awssdk
bom
- 2.20.45
+ 2.20.112
+ pom
+ import
+
+
+ org.apache.logging.log4j
+ log4j-bom
+ 2.20.0
pom
import
@@ -70,6 +78,14 @@
software.amazon.awssdk
iam
+
+ software.amazon.awssdk
+ iam-policy-builder
+
+
+ software.amazon.awssdk
+ dynamodb
+
com.googlecode.json-simple
json-simple
@@ -87,5 +103,31 @@
software.amazon.awssdk
sts
+
+ software.amazon.awssdk
+ sso
+
+
+ software.amazon.awssdk
+ ssooidc
+
+
+ org.apache.logging.log4j
+ log4j-slf4j2-impl
+
+
+ software.amazon.awssdk
+ accessanalyzer
+
+
+
+
+
+ org.slf4j
+ jcl-over-slf4j
+ ${slf4j.version}
+
+
\ No newline at end of file
diff --git a/javav2/example_code/iam/src/main/java/com/example/iam/IamPolicyBuilderExamples.java b/javav2/example_code/iam/src/main/java/com/example/iam/IamPolicyBuilderExamples.java
new file mode 100644
index 00000000000..9551ef2831f
--- /dev/null
+++ b/javav2/example_code/iam/src/main/java/com/example/iam/IamPolicyBuilderExamples.java
@@ -0,0 +1,249 @@
+/*
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ * SPDX-License-Identifier: Apache-2.0
+ */
+package com.example.iam;
+
+// snippet-start:[iam.java2.policy_builder.policy_builder_examples.imports]
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import software.amazon.awssdk.policybuilder.iam.IamConditionOperator;
+import software.amazon.awssdk.policybuilder.iam.IamEffect;
+import software.amazon.awssdk.policybuilder.iam.IamPolicy;
+import software.amazon.awssdk.policybuilder.iam.IamPolicyWriter;
+import software.amazon.awssdk.policybuilder.iam.IamPrincipal;
+import software.amazon.awssdk.policybuilder.iam.IamPrincipalType;
+import software.amazon.awssdk.policybuilder.iam.IamResource;
+import software.amazon.awssdk.policybuilder.iam.IamStatement;
+import software.amazon.awssdk.regions.Region;
+import software.amazon.awssdk.services.iam.IamClient;
+import software.amazon.awssdk.services.iam.model.GetPolicyResponse;
+import software.amazon.awssdk.services.iam.model.GetPolicyVersionResponse;
+import software.amazon.awssdk.services.sts.StsClient;
+
+import java.net.URLDecoder;
+import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
+import java.util.List;
+// snippet-end:[iam.java2.policy_builder.policy_builder_examples.imports]
+
+public class IamPolicyBuilderExamples {
+ private static final Logger logger = LoggerFactory.getLogger(IamPolicyBuilderExamples.class);
+
+ public static void main(String[] args) {
+ IamPolicyBuilderExamples iamPolicyBuilderExamples = new IamPolicyBuilderExamples();
+ // snippet-start:[iam.java2.policy_builder.policy_builder_examples.iamclient_build]
+ IamClient iam = IamClient.builder().region(Region.AWS_GLOBAL).build();
+ // snippet-end:[iam.java2.policy_builder.policy_builder_examples.iamclient_build]
+
+ iamPolicyBuilderExamples.runCreateAndUploadPolicyExample(iam);
+ iamPolicyBuilderExamples.runCreateNewBasedOnExisingPolicyExample(iam);
+
+ if (iam != null) {
+ iam.close();
+ }
+
+ iamPolicyBuilderExamples.runTimeBasedPolicyExample();
+ iamPolicyBuilderExamples.runMultipleConditionsExample();
+ iamPolicyBuilderExamples.runSpecifyPrincipalsExample();
+ iamPolicyBuilderExamples.runAllowCrossAccountAccessExample();
+ }
+
+ // snippet-start:[iam.java2.policy_builder.create_and_upload_policy]
+ public String createAndUploadPolicyExample(IamClient iam, String accountID, String policyName) {
+ // Build the policy.
+ IamPolicy policy =
+ IamPolicy.builder() // 'version' defaults to "2012-10-17".
+ .addStatement(IamStatement.builder()
+ .effect(IamEffect.ALLOW)
+ .addAction("dynamodb:PutItem")
+ .addResource("arn:aws:dynamodb:us-east-1:" + accountID + ":table/exampleTableName")
+ .build())
+ .build();
+ // Upload the policy.
+ iam.createPolicy(r -> r.policyName(policyName).policyDocument(policy.toJson()));
+ return policy.toJson(IamPolicyWriter.builder().prettyPrint(true).build());
+ }
+ // snippet-end:[iam.java2.policy_builder.create_and_upload_policy]
+
+ private void runCreateAndUploadPolicyExample(IamClient iam) {
+ String accountId = getAccountID();
+ String policyName = "AllowPutItemToExampleTable";
+
+ String jsonPolicy = createAndUploadPolicyExample(iam, accountId, policyName);
+ logger.info(jsonPolicy);
+
+ GetPolicyResponse putItemPolicy = iam.getPolicy(b -> b.policyArn("arn:aws:iam::" + accountId + ":policy/" + policyName));
+ iam.deletePolicy(b -> b.policyArn(putItemPolicy.policy().arn()));
+ logger.info("Policy [{}] deleted", putItemPolicy.policy().arn());
+ }
+
+ // snippet-start:[iam.java2.policy_builder.create_new_based_on_existing_policy]
+ public String createNewBasedOnExistingPolicyExample(IamClient iam, String accountID, String policyName, String newPolicyName) {
+
+ String policyArn = "arn:aws:iam::" + accountID + ":policy/" + policyName;
+ GetPolicyResponse getPolicyResponse = iam.getPolicy(r -> r.policyArn(policyArn));
+
+ String policyVersion = getPolicyResponse.policy().defaultVersionId();
+ GetPolicyVersionResponse getPolicyVersionResponse =
+ iam.getPolicyVersion(r -> r.policyArn(policyArn).versionId(policyVersion));
+
+ // Create an IamPolicy instance from the JSON string returned from IAM.
+ String decodedPolicy = URLDecoder.decode(getPolicyVersionResponse.policyVersion().document(), StandardCharsets.UTF_8);
+ IamPolicy policy = IamPolicy.fromJson(decodedPolicy);
+
+ /*
+ All IamPolicy components are immutable, so use the copy method that creates a new instance that
+ can be altered in the same method call.
+
+ Add the ability to get an item from DynamoDB as an additional action.
+ */
+ IamStatement newStatement = policy.statements().get(0).copy(s -> s.addAction("dynamodb:GetItem"));
+
+ // Create a new statement that replaces the original statement.
+ IamPolicy newPolicy = policy.copy(p -> p.statements(Arrays.asList(newStatement)));
+
+ // Upload the new policy. IAM now has both policies.
+ iam.createPolicy(r -> r.policyName(newPolicyName)
+ .policyDocument(newPolicy.toJson()));
+
+ return newPolicy.toJson(IamPolicyWriter.builder().prettyPrint(true).build());
+ }
+ // snippet-end:[iam.java2.policy_builder.create_new_based_on_existing_policy]
+
+ private void runCreateNewBasedOnExisingPolicyExample(IamClient iam) {
+ String accountID = getAccountID();
+ String policyName = "AllowPutItemToExampleTable";
+ String newPolicyName = "AllowGetAndPutItemToExampleTable";
+ // First part of the example is to create the policy.
+ String jsonPolicy = createAndUploadPolicyExample(iam, accountID, policyName);
+ logger.info(jsonPolicy);
+
+ String jsonNewPolicy = createNewBasedOnExistingPolicyExample(iam, accountID, policyName, newPolicyName);
+ logger.info(jsonNewPolicy);
+
+ // Delete the two policies
+ GetPolicyResponse putItemPolicy = iam.getPolicy(b -> b.policyArn("arn:aws:iam::" + accountID + ":policy/" + policyName));
+ iam.deletePolicy(b -> b.policyArn(putItemPolicy.policy().arn()));
+ logger.info("Policy [{}] deleted", putItemPolicy.policy().arn());
+
+ GetPolicyResponse getAndPutItemPolicy = iam.getPolicy(b -> b.policyArn("arn:aws:iam::" + accountID + ":policy/" + newPolicyName));
+ iam.deletePolicy(b -> b.policyArn(getAndPutItemPolicy.policy().arn()));
+ logger.info("Policy [{}] deleted", getAndPutItemPolicy.policy().arn());
+ }
+
+ // snippet-start:[iam.java2.policy_builder.multiple_conditions]
+ public String multipleConditionsExample() {
+ IamPolicy policy = IamPolicy.builder()
+ .addStatement(b -> b
+ .effect(IamEffect.ALLOW)
+ .addAction("dynamodb:GetItem")
+ .addAction("dynamodb:BatchGetItem")
+ .addAction("dynamodb:Query")
+ .addAction("dynamodb:PutItem")
+ .addAction("dynamodb:UpdateItem")
+ .addAction("dynamodb:DeleteItem")
+ .addAction("dynamodb:BatchWriteItem")
+ .addResource("arn:aws:dynamodb:*:*:table/table-name")
+ .addConditions(IamConditionOperator.STRING_EQUALS.addPrefix("ForAllValues:"),
+ "dynamodb:Attributes",
+ List.of("column-name1", "column-name2", "column-name3"))
+ .addCondition(b1 -> b1.operator(IamConditionOperator.STRING_EQUALS.addSuffix("IfExists"))
+ .key("dynamodb:Select")
+ .value("SPECIFIC_ATTRIBUTES")))
+ .build();
+
+ return policy.toJson(IamPolicyWriter.builder()
+ .prettyPrint(true).build());
+ }
+ // snippet-end:[iam.java2.policy_builder.multiple_conditions]
+
+ private void runMultipleConditionsExample() {
+ String jsonPolicy = multipleConditionsExample();
+ logger.info(jsonPolicy);
+
+ }
+
+ // snippet-start:[iam.java2.policy_builder.time_based]
+ public String timeBasedPolicyExample() {
+ IamPolicy policy = IamPolicy.builder()
+ .addStatement(b -> b
+ .effect(IamEffect.ALLOW)
+ .addAction("dynamodb:GetItem")
+ .addResource(IamResource.ALL)
+ .addCondition(b1 -> b1
+ .operator(IamConditionOperator.DATE_GREATER_THAN)
+ .key("aws:CurrentTime")
+ .value("2020-04-01T00:00:00Z"))
+ .addCondition(b1 -> b1
+ .operator(IamConditionOperator.DATE_LESS_THAN)
+ .key("aws:CurrentTime")
+ .value("2020-06-30T23:59:59Z")))
+ .build();
+
+ // Use an IamPolicyWriter to write out the JSON string to a more readable format.
+ return policy.toJson(IamPolicyWriter.builder()
+ .prettyPrint(true)
+ .build());
+ }
+ // snippet-end:[iam.java2.policy_builder.time_based]
+
+ private void runTimeBasedPolicyExample() {
+ String policyJson = timeBasedPolicyExample();
+ logger.info(policyJson);
+ }
+
+ // snippet-start:[iam.java2.policy_builder.specify_principals]
+ public String specifyPrincipalsExample() {
+ IamPolicy policy = IamPolicy.builder()
+ .addStatement(b -> b
+ .effect(IamEffect.DENY)
+ .addAction("s3:*")
+ .addPrincipal(IamPrincipal.ALL)
+ .addResource("arn:aws:s3:::BUCKETNAME/*")
+ .addResource("arn:aws:s3:::BUCKETNAME")
+ .addCondition(b1 -> b1
+ .operator(IamConditionOperator.ARN_NOT_EQUALS)
+ .key("aws:PrincipalArn")
+ .value("arn:aws:iam::444455556666:user/user-name")))
+ .build();
+ return policy.toJson(IamPolicyWriter.builder()
+ .prettyPrint(true).build());
+ }
+ // snippet-end:[iam.java2.policy_builder.specify_principals]
+
+ private void runSpecifyPrincipalsExample() {
+ String policyJson = specifyPrincipalsExample();
+ logger.info(policyJson);
+ }
+
+ // snippet-start:[iam.java2.policy_builder.allow_cross_account_access]
+ public String allowCrossAccountAccessExample() {
+ IamPolicy policy = IamPolicy.builder()
+ .addStatement(b -> b
+ .effect(IamEffect.ALLOW)
+ .addPrincipal(IamPrincipalType.AWS, "111122223333")
+ .addAction("s3:PutObject")
+ .addResource("arn:aws:s3:::DOC-EXAMPLE-BUCKET/*")
+ .addCondition(b1 -> b1
+ .operator(IamConditionOperator.STRING_EQUALS)
+ .key("s3:x-amz-acl")
+ .value("bucket-owner-full-control")))
+ .build();
+ return policy.toJson(IamPolicyWriter.builder()
+ .prettyPrint(true).build());
+ }
+ // snippet-end:[iam.java2.policy_builder.allow_cross_account_access]
+
+ private void runAllowCrossAccountAccessExample() {
+ String policyJson = allowCrossAccountAccessExample();
+ logger.info(policyJson);
+ }
+
+ String getAccountID() {
+ try (StsClient stsClient = StsClient.create()) {
+ return stsClient.getCallerIdentity().account();
+ }
+ }
+}
diff --git a/javav2/example_code/iam/src/main/resources/log4j2.xml b/javav2/example_code/iam/src/main/resources/log4j2.xml
new file mode 100644
index 00000000000..f212ad40e01
--- /dev/null
+++ b/javav2/example_code/iam/src/main/resources/log4j2.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/javav2/example_code/iam/src/test/java/com/example/iam/IamPolicyBuilderExamplesTest.java b/javav2/example_code/iam/src/test/java/com/example/iam/IamPolicyBuilderExamplesTest.java
new file mode 100644
index 00000000000..b203764751f
--- /dev/null
+++ b/javav2/example_code/iam/src/test/java/com/example/iam/IamPolicyBuilderExamplesTest.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ * SPDX-License-Identifier: Apache-2.0
+ */
+package com.example.iam;
+
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Tag;
+import org.junit.jupiter.api.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import software.amazon.awssdk.regions.Region;
+import software.amazon.awssdk.services.accessanalyzer.AccessAnalyzerClient;
+import software.amazon.awssdk.services.accessanalyzer.model.PolicyType;
+import software.amazon.awssdk.services.accessanalyzer.model.ValidatePolicyResponse;
+import software.amazon.awssdk.services.iam.IamClient;
+import software.amazon.awssdk.services.iam.model.GetPolicyResponse;
+
+class IamPolicyBuilderExamplesTest {
+ private static final Logger logger = LoggerFactory.getLogger(IamPolicyBuilderExamplesTest.class);
+ private IamPolicyBuilderExamples examples;
+ private IamClient iam;
+
+ private static void analyze(String policyJson, PolicyType policyType) {
+ try (AccessAnalyzerClient analyzerClient = AccessAnalyzerClient.create()) {
+ final ValidatePolicyResponse response = analyzerClient.validatePolicy(b -> b
+ .policyDocument(policyJson)
+ .policyType(policyType));
+ response.findings().forEach(f ->
+ logger.info("Type [{}]; Detail [{}]", f.findingType().name(), f.findingDetails()));
+ Assertions.assertEquals(0, response.findings().size());
+ }
+ }
+
+ @BeforeEach
+ void setUp() {
+ examples = new IamPolicyBuilderExamples();
+ iam = IamClient.builder().region(Region.AWS_GLOBAL).build();
+ }
+
+ @AfterEach
+ void tearDown() {
+ if (iam != null) {
+ iam.close();
+ }
+ }
+
+ /**
+ * If this test succeeds, the syntax of the policy that is created is checked by the IAM service on upload.
+ */
+ @Test
+ @Tag("IntegrationTest")
+ void createAndUploadPolicyExample() {
+ String accountId = examples.getAccountID();
+ String policyName = "AllowPutItemToExampleTable";
+ String jsonPolicy = examples.createAndUploadPolicyExample(iam, accountId, policyName);
+ logger.info(jsonPolicy);
+
+ GetPolicyResponse putItemPolicy = iam.getPolicy(b -> b.policyArn("arn:aws:iam::" + accountId + ":policy/" + policyName));
+ iam.deletePolicy(b -> b.policyArn(putItemPolicy.policy().arn()));
+ logger.info("Policy [{}] deleted", putItemPolicy.policy().arn());
+ }
+
+ /**
+ * If this test succeeds, the syntax of the policies that are created and uploaded will be checked by the IAM service.
+ */
+ @Test
+ @Tag("IntegrationTest")
+ void createNewBasedOnExisingPolicyExample() {
+ String accountID = examples.getAccountID();
+ String policyName = "AllowPutItemToExampleTable";
+ String newPolicyName = "AllowGetAndPutItemToExampleTable";
+ // First part of the example is to create the policy.
+ String jsonPolicy = examples.createAndUploadPolicyExample(iam, accountID, policyName);
+ logger.info(jsonPolicy);
+
+ String jsonNewPolicy = examples.createNewBasedOnExistingPolicyExample(iam, accountID, policyName, newPolicyName);
+ logger.info(jsonNewPolicy);
+
+ // Delete the two policies
+ GetPolicyResponse putItemPolicy = iam.getPolicy(b -> b.policyArn("arn:aws:iam::" + accountID + ":policy/" + policyName));
+ iam.deletePolicy(b -> b.policyArn(putItemPolicy.policy().arn()));
+ logger.info("Policy [{}] deleted", putItemPolicy.policy().arn());
+
+ GetPolicyResponse getAndPutItemPolicy = iam.getPolicy(b -> b.policyArn("arn:aws:iam::" + accountID + ":policy/" + newPolicyName));
+ iam.deletePolicy(b -> b.policyArn(getAndPutItemPolicy.policy().arn()));
+ logger.info("Policy [{}] deleted", getAndPutItemPolicy.policy().arn());
+ }
+
+ @Test
+ @Tag("IntegrationTest")
+ void multipleConditionsExample() {
+ String jsonPolicy = examples.multipleConditionsExample();
+ logger.info(jsonPolicy);
+ analyze(jsonPolicy, PolicyType.IDENTITY_POLICY);
+ }
+
+ @Test
+ @Tag("IntegrationTest")
+ void timeBasedPolicyExample() {
+ String policyJson = examples.timeBasedPolicyExample();
+ logger.info(policyJson);
+ analyze(policyJson, PolicyType.IDENTITY_POLICY);
+ }
+
+ @Test
+ @Tag("IntegrationTest")
+ void specifyPrincipalsExample() {
+ String policyJson = examples.specifyPrincipalsExample();
+ logger.info(policyJson);
+ analyze(policyJson, PolicyType.RESOURCE_POLICY);
+
+ }
+
+ @Test
+ @Tag("IntegrationTest")
+ void allowCrossAccountAccessExample() {
+ String policyJson = examples.allowCrossAccountAccessExample();
+ logger.info(policyJson);
+ analyze(policyJson, PolicyType.RESOURCE_POLICY);
+ }
+
+}
\ No newline at end of file