From addd875d73ff08455954762e92ce0e45afa5f0e8 Mon Sep 17 00:00:00 2001 From: Fink Date: Mon, 7 Oct 2019 12:27:04 -0700 Subject: [PATCH] Adding support for S3 control --- aws-sdk-java/pom.xml | 5 + bom/pom.xml | 5 + pom.xml | 4 + services/pom.xml | 1 + services/s3control/pom.xml | 77 + .../S3ControlIntegrationTest.java | 137 ++ .../s3control/S3ControlConfiguration.java | 151 ++ .../EndpointAddressInterceptor.java | 91 ++ .../PayloadSigningInterceptor.java | 42 + .../codegen-resources/customization.config | 7 + .../codegen-resources/paginators-1.json | 9 + .../codegen-resources/service-2.json | 1352 +++++++++++++++++ .../services/s3control/execution.interceptors | 2 + .../EndpointAddressInterceptorTest.java | 154 ++ .../PayloadSigningInterceptorTest.java | 102 ++ 15 files changed, 2139 insertions(+) create mode 100644 services/s3control/pom.xml create mode 100644 services/s3control/src/it/java/software.amazon.awssdk.services.s3control/S3ControlIntegrationTest.java create mode 100644 services/s3control/src/main/java/software/amazon/awssdk/services/s3control/S3ControlConfiguration.java create mode 100644 services/s3control/src/main/java/software/amazon/awssdk/services/s3control/internal/interceptors/EndpointAddressInterceptor.java create mode 100644 services/s3control/src/main/java/software/amazon/awssdk/services/s3control/internal/interceptors/PayloadSigningInterceptor.java create mode 100644 services/s3control/src/main/resources/codegen-resources/customization.config create mode 100644 services/s3control/src/main/resources/codegen-resources/paginators-1.json create mode 100644 services/s3control/src/main/resources/codegen-resources/service-2.json create mode 100644 services/s3control/src/main/resources/software/amazon/awssdk/services/s3control/execution.interceptors create mode 100644 services/s3control/src/test/java/software/amazon/awssdk/services/s3control/internal/interceptors/EndpointAddressInterceptorTest.java create mode 100644 services/s3control/src/test/java/software/amazon/awssdk/services/s3control/internal/interceptors/PayloadSigningInterceptorTest.java diff --git a/aws-sdk-java/pom.xml b/aws-sdk-java/pom.xml index 0df3dad6891d..4e38ee4ce64f 100644 --- a/aws-sdk-java/pom.xml +++ b/aws-sdk-java/pom.xml @@ -710,6 +710,11 @@ Amazon AutoScaling, etc). s3 ${awsjavasdk.version} + + software.amazon.awssdk + s3control + ${awsjavasdk.version} + software.amazon.awssdk sagemaker diff --git a/bom/pom.xml b/bom/pom.xml index 81dc8b13cbef..ea4fa43dccc6 100644 --- a/bom/pom.xml +++ b/bom/pom.xml @@ -820,6 +820,11 @@ s3 ${awsjavasdk.version} + + software.amazon.awssdk + s3control + ${awsjavasdk.version} + software.amazon.awssdk sagemaker diff --git a/pom.xml b/pom.xml index b99359090472..eb6303d8bb9b 100644 --- a/pom.xml +++ b/pom.xml @@ -727,6 +727,10 @@ Resource Groups Tagging API software.amazon.awssdk.services.resourcegroupstaggingapi* + + S3 Control + software.amazon.awssdk.services.s3control* + S3 software.amazon.awssdk.services.s3* diff --git a/services/pom.xml b/services/pom.xml index da98418b12ea..a034ad8c0a09 100644 --- a/services/pom.xml +++ b/services/pom.xml @@ -90,6 +90,7 @@ route53 route53domains s3 + s3control sms servicecatalog ses diff --git a/services/s3control/pom.xml b/services/s3control/pom.xml new file mode 100644 index 000000000000..3797bd548eef --- /dev/null +++ b/services/s3control/pom.xml @@ -0,0 +1,77 @@ + + + + + 4.0.0 + + software.amazon.awssdk + services + 2.9.16-SNAPSHOT + + s3control + AWS Java SDK :: Services :: Amazon S3 Control + The AWS Java SDK for Amazon S3 Control module holds the client classes that are used for communicating with + Amazon Simple Storage Service Control Plane + + https://aws.amazon.com/sdkforjava + + + + org.apache.maven.plugins + maven-jar-plugin + + + + software.amazon.awssdk.services.s3control + + + + + + + + + + software.amazon.awssdk + aws-xml-protocol + ${awsjavasdk.version} + + + software.amazon.awssdk + protocol-core + ${awsjavasdk.version} + + + + commons-io + commons-io + test + + + org.apache.commons + commons-lang3 + test + + + software.amazon.awssdk + sts + ${awsjavasdk.version} + test + + + diff --git a/services/s3control/src/it/java/software.amazon.awssdk.services.s3control/S3ControlIntegrationTest.java b/services/s3control/src/it/java/software.amazon.awssdk.services.s3control/S3ControlIntegrationTest.java new file mode 100644 index 000000000000..6cf33e0195b2 --- /dev/null +++ b/services/s3control/src/it/java/software.amazon.awssdk.services.s3control/S3ControlIntegrationTest.java @@ -0,0 +1,137 @@ +/* + * Copyright 2010-2019 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.awssdk.services.s3control; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Fail.fail; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import software.amazon.awssdk.core.interceptor.Context; +import software.amazon.awssdk.core.interceptor.ExecutionAttributes; +import software.amazon.awssdk.core.interceptor.ExecutionInterceptor; +import software.amazon.awssdk.http.SdkHttpFullRequest; +import software.amazon.awssdk.services.s3control.model.DeletePublicAccessBlockRequest; +import software.amazon.awssdk.services.s3control.model.GetPublicAccessBlockResponse; +import software.amazon.awssdk.services.s3control.model.NoSuchPublicAccessBlockConfigurationException; +import software.amazon.awssdk.services.s3control.model.PutPublicAccessBlockResponse; +import software.amazon.awssdk.services.s3control.model.S3ControlException; +import software.amazon.awssdk.services.sts.StsClient; +import software.amazon.awssdk.testutils.service.AwsIntegrationTestBase; + +public class S3ControlIntegrationTest extends AwsIntegrationTestBase { + + private String accountId; + + private static final String INVALID_ACCOUNT_ID = "1"; + + private S3ControlClient client; + + @Before + public void setup() { + StsClient sts = StsClient.create(); + accountId = sts.getCallerIdentity().account(); + client = S3ControlClient.builder() + .overrideConfiguration(o -> o.addExecutionInterceptor(new AssertPayloadIsSignedExecutionInterceptor())) + .build(); + } + + @After + public void tearDown() { + try { + client.deletePublicAccessBlock(DeletePublicAccessBlockRequest.builder().accountId(accountId).build()); + } catch (Exception ignore) { + + } + } + + @Test + public void putGetAndDeletePublicAccessBlock_ValidAccount() throws InterruptedException { + PutPublicAccessBlockResponse result = + client.putPublicAccessBlock(r -> r.accountId(accountId) + .publicAccessBlockConfiguration(r2 -> r2.blockPublicAcls(true) + .ignorePublicAcls(true))); + assertNotNull(result); + + // Wait a bit for the put to take affect + Thread.sleep(5000); + + GetPublicAccessBlockResponse config = client.getPublicAccessBlock(r -> r.accountId(accountId)); + assertTrue(config.publicAccessBlockConfiguration().blockPublicAcls()); + assertTrue(config.publicAccessBlockConfiguration().ignorePublicAcls()); + + assertNotNull(client.deletePublicAccessBlock(r -> r.accountId(accountId))); + } + + @Test + public void putPublicAccessBlock_NoSuchAccount() { + try { + assertNotNull(client.putPublicAccessBlock(r -> r.accountId(INVALID_ACCOUNT_ID) + .publicAccessBlockConfiguration(r2 -> r2.restrictPublicBuckets(true)))); + fail("Expected exception"); + } catch (S3ControlException e) { + assertEquals("AccessDenied", e.awsErrorDetails().errorCode()); + assertNotNull(e.requestId()); + } + } + + @Test + public void getPublicAccessBlock_NoSuchAccount() { + try { + client.getPublicAccessBlock(r -> r.accountId(INVALID_ACCOUNT_ID)); + fail("Expected exception"); + } catch (S3ControlException e) { + assertEquals("AccessDenied", e.awsErrorDetails().errorCode()); + assertNotNull(e.requestId()); + } + } + + @Test + public void getPublicAccessBlock_NoSuchConfig() { + try { + client.getPublicAccessBlock(r -> r.accountId(accountId)); + fail("Expected exception"); + } catch (NoSuchPublicAccessBlockConfigurationException e) { + assertNotNull(e.requestId()); + } + } + + @Test + public void deletePublicAccessBlock_NoSuchAccount() { + try { + client.deletePublicAccessBlock(r -> r.accountId(INVALID_ACCOUNT_ID)); + fail("Expected exception"); + } catch (S3ControlException e) { + assertEquals("AccessDenied", e.awsErrorDetails().errorCode()); + assertNotNull(e.requestId()); + } + } + + /** + * Request handler to assert that payload signing is enabled. + */ + private static final class AssertPayloadIsSignedExecutionInterceptor implements ExecutionInterceptor { + @Override + public void afterTransmission(Context.AfterTransmission context, ExecutionAttributes executionAttributes) { + SdkHttpFullRequest request = (SdkHttpFullRequest) context.httpRequest(); + assertThat(context.httpRequest().headers().get("x-amz-content-sha256").get(0)).doesNotContain("UNSIGNED-PAYLOAD"); + } + } + +} \ No newline at end of file diff --git a/services/s3control/src/main/java/software/amazon/awssdk/services/s3control/S3ControlConfiguration.java b/services/s3control/src/main/java/software/amazon/awssdk/services/s3control/S3ControlConfiguration.java new file mode 100644 index 000000000000..0c234733cb51 --- /dev/null +++ b/services/s3control/src/main/java/software/amazon/awssdk/services/s3control/S3ControlConfiguration.java @@ -0,0 +1,151 @@ +/* + * Copyright 2010-2019 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.awssdk.services.s3control; + +import software.amazon.awssdk.annotations.Immutable; +import software.amazon.awssdk.annotations.NotThreadSafe; +import software.amazon.awssdk.annotations.SdkPublicApi; +import software.amazon.awssdk.annotations.ThreadSafe; +import software.amazon.awssdk.core.ServiceConfiguration; +import software.amazon.awssdk.utils.builder.CopyableBuilder; +import software.amazon.awssdk.utils.builder.ToCopyableBuilder; + +/** + * S3 Control specific configuration allowing customers to enabled FIPS or + * dualstack. + */ +@SdkPublicApi +@Immutable +@ThreadSafe +public final class S3ControlConfiguration implements ServiceConfiguration, + ToCopyableBuilder { + /** + * S3 FIPS mode is by default not enabled + */ + private static final boolean DEFAULT_FIPS_MODE_ENABLED = false; + + /** + * S3 Dualstack endpoint is by default not enabled + */ + private static final boolean DEFAULT_DUALSTACK_ENABLED = false; + + private final boolean fipsModeEnabled; + private final boolean dualstackEnabled; + + private S3ControlConfiguration(DefaultS3ServiceConfigurationBuilder builder) { + this.dualstackEnabled = resolveBoolean(builder.dualstackEnabled, DEFAULT_DUALSTACK_ENABLED); + this.fipsModeEnabled = resolveBoolean(builder.fipsModeEnabled, DEFAULT_FIPS_MODE_ENABLED); + } + + /** + * Create a {@link Builder}, used to create a {@link S3ControlConfiguration}. + */ + public static Builder builder() { + return new DefaultS3ServiceConfigurationBuilder(); + } + + /** + *

+ * Returns whether the client has enabled fips mode for accessing S3 Control. + * + * @return True if client will use FIPS mode. + */ + public boolean fipsModeEnabled() { + return fipsModeEnabled; + } + + /** + *

+ * Returns whether the client is configured to use dualstack mode for + * accessing S3. If you want to use IPv6 when accessing S3, dualstack + * must be enabled. + *

+ * + *

+ * Dualstack endpoints are disabled by default. + *

+ * + * @return True if the client will use the dualstack endpoints + */ + public boolean dualstackEnabled() { + return dualstackEnabled; + } + + private boolean resolveBoolean(Boolean suppliedValue, boolean defaultValue) { + return suppliedValue == null ? defaultValue : suppliedValue; + } + + @Override + public Builder toBuilder() { + return builder() + .dualstackEnabled(dualstackEnabled) + .fipsModeEnabled(fipsModeEnabled); + } + + @NotThreadSafe + public interface Builder extends CopyableBuilder { + /** + * Option to enable using the dualstack endpoints when accessing S3. Dualstack + * should be enabled if you want to use IPv6. + * + *

+ * Dualstack endpoints are disabled by default. + *

+ * + * @see S3ControlConfiguration#dualstackEnabled(). + */ + Builder dualstackEnabled(Boolean dualstackEnabled); + + /** + * Option to enable using the fips endpoint when accessing S3 Control. + * + *

+ * FIPS mode is disabled by default. + *

+ * + * @see S3ControlConfiguration#fipsModeEnabled(). + */ + Builder fipsModeEnabled(Boolean fipsModeEnabled); + } + + private static final class DefaultS3ServiceConfigurationBuilder implements Builder { + + private Boolean dualstackEnabled; + private Boolean fipsModeEnabled; + + public Builder dualstackEnabled(Boolean dualstackEnabled) { + this.dualstackEnabled = dualstackEnabled; + return this; + } + + public void setDualstackEnabled(Boolean dualstackEnabled) { + dualstackEnabled(dualstackEnabled); + } + + public Builder fipsModeEnabled(Boolean fipsModeEnabled) { + this.fipsModeEnabled = fipsModeEnabled; + return this; + } + + public void setFipsModeEnabled(Boolean fipsModeEnabled) { + fipsModeEnabled(fipsModeEnabled); + } + + public S3ControlConfiguration build() { + return new S3ControlConfiguration(this); + } + } +} diff --git a/services/s3control/src/main/java/software/amazon/awssdk/services/s3control/internal/interceptors/EndpointAddressInterceptor.java b/services/s3control/src/main/java/software/amazon/awssdk/services/s3control/internal/interceptors/EndpointAddressInterceptor.java new file mode 100644 index 000000000000..86afc1440364 --- /dev/null +++ b/services/s3control/src/main/java/software/amazon/awssdk/services/s3control/internal/interceptors/EndpointAddressInterceptor.java @@ -0,0 +1,91 @@ +/* + * Copyright 2010-2019 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.awssdk.services.s3control.internal.interceptors; + +import java.net.URI; +import software.amazon.awssdk.annotations.SdkInternalApi; +import software.amazon.awssdk.auth.signer.AwsSignerExecutionAttribute; +import software.amazon.awssdk.core.exception.SdkClientException; +import software.amazon.awssdk.core.interceptor.Context; +import software.amazon.awssdk.core.interceptor.ExecutionAttributes; +import software.amazon.awssdk.core.interceptor.ExecutionInterceptor; +import software.amazon.awssdk.http.SdkHttpRequest; +import software.amazon.awssdk.services.s3control.S3ControlConfiguration; + +/** + * Execution interceptor which modifies the HTTP request to S3 Control to + * change the endpoint to the correct endpoint. This includes prefixing the AWS + * account identifier and, when enabled, adding in FIPS and dualstack. + */ +@SdkInternalApi +public class EndpointAddressInterceptor implements ExecutionInterceptor { + + private static final String ENDPOINT_PREFIX = "s3-control"; + + private static final String X_AMZ_ACCOUNT_ID = "x-amz-account-id"; + + @Override + public SdkHttpRequest modifyHttpRequest(Context.ModifyHttpRequest context, + ExecutionAttributes executionAttributes) { + SdkHttpRequest request = context.httpRequest(); + + if (!request.headers().containsKey(X_AMZ_ACCOUNT_ID)) { + throw SdkClientException.create("Account ID must be specified for all requests"); + } + + String accountId = request.headers().get(X_AMZ_ACCOUNT_ID).get(0); + URI endpoint = request.getUri(); + + S3ControlConfiguration config = (S3ControlConfiguration) executionAttributes.getAttribute( + AwsSignerExecutionAttribute.SERVICE_CONFIG); + + String host = resolveHost(request, accountId, config); + + return request.toBuilder() + .host(host) + .build(); + } + + private String resolveHost(SdkHttpRequest request, String accountId, S3ControlConfiguration configuration) { + if (isDualstackEnabled(configuration) && isFipsEnabled(configuration)) { + throw SdkClientException.create("Cannot use both Dual-Stack endpoints and FIPS endpoints"); + } + String host = request.getUri().getHost(); + if (isDualstackEnabled(configuration)) { + if (!host.contains(ENDPOINT_PREFIX)) { + throw SdkClientException.create(String.format("The Dual-Stack option cannot be used with custom endpoints (%s)", + request.getUri())); + } + host = host.replace(ENDPOINT_PREFIX, String.format("%s.%s", ENDPOINT_PREFIX, "dualstack")); + } else if (isFipsEnabled(configuration)) { + if (!host.contains(ENDPOINT_PREFIX)) { + throw SdkClientException.create(String.format("The FIPS option cannot be used with custom endpoints (%s)", + request.getUri())); + } + host = host.replace(ENDPOINT_PREFIX, String.format("%s-%s", ENDPOINT_PREFIX, "fips")); + + } + return String.format("%s.%s", accountId, host); + } + + private boolean isDualstackEnabled(S3ControlConfiguration configuration) { + return configuration != null && configuration.dualstackEnabled(); + } + + private boolean isFipsEnabled(S3ControlConfiguration configuration) { + return configuration != null && configuration.fipsModeEnabled(); + } +} diff --git a/services/s3control/src/main/java/software/amazon/awssdk/services/s3control/internal/interceptors/PayloadSigningInterceptor.java b/services/s3control/src/main/java/software/amazon/awssdk/services/s3control/internal/interceptors/PayloadSigningInterceptor.java new file mode 100644 index 000000000000..f46a4627881d --- /dev/null +++ b/services/s3control/src/main/java/software/amazon/awssdk/services/s3control/internal/interceptors/PayloadSigningInterceptor.java @@ -0,0 +1,42 @@ +/* + * Copyright 2010-2019 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.awssdk.services.s3control.internal.interceptors; + +import java.util.Optional; +import software.amazon.awssdk.annotations.SdkInternalApi; +import software.amazon.awssdk.auth.signer.S3SignerExecutionAttribute; +import software.amazon.awssdk.core.interceptor.Context; +import software.amazon.awssdk.core.interceptor.ExecutionAttributes; +import software.amazon.awssdk.core.interceptor.ExecutionInterceptor; +import software.amazon.awssdk.core.sync.RequestBody; +import software.amazon.awssdk.http.SdkHttpMethod; + +/** + * Turns on payload signing and prevents moving query params to body during a POST which S3 doesn't like. + */ +@SdkInternalApi +public class PayloadSigningInterceptor implements ExecutionInterceptor { + + public Optional modifyHttpContent(Context.ModifyHttpRequest context, + ExecutionAttributes executionAttributes) { + executionAttributes.putAttribute(S3SignerExecutionAttribute.ENABLE_PAYLOAD_SIGNING, true); + if (!context.requestBody().isPresent() && context.httpRequest().method().equals(SdkHttpMethod.POST)) { + return Optional.of(RequestBody.fromBytes(new byte[0])); + } + + return context.requestBody(); + } +} diff --git a/services/s3control/src/main/resources/codegen-resources/customization.config b/services/s3control/src/main/resources/codegen-resources/customization.config new file mode 100644 index 000000000000..37befeb4c83b --- /dev/null +++ b/services/s3control/src/main/resources/codegen-resources/customization.config @@ -0,0 +1,7 @@ +{ + "serviceSpecificClientConfigClass": "S3ControlConfiguration", + "customResponseMetadata": { + "EXTENDED_REQUEST_ID": "x-amz-id-2", + "REQUEST_ID": "x-amz-request-id" + } +} \ No newline at end of file diff --git a/services/s3control/src/main/resources/codegen-resources/paginators-1.json b/services/s3control/src/main/resources/codegen-resources/paginators-1.json new file mode 100644 index 000000000000..886110429dda --- /dev/null +++ b/services/s3control/src/main/resources/codegen-resources/paginators-1.json @@ -0,0 +1,9 @@ +{ + "pagination": { + "ListJobs": { + "input_token": "NextToken", + "output_token": "NextToken", + "limit_key": "MaxResults" + } + } +} diff --git a/services/s3control/src/main/resources/codegen-resources/service-2.json b/services/s3control/src/main/resources/codegen-resources/service-2.json new file mode 100644 index 000000000000..6314cf841fe4 --- /dev/null +++ b/services/s3control/src/main/resources/codegen-resources/service-2.json @@ -0,0 +1,1352 @@ +{ + "version":"2.0", + "metadata":{ + "apiVersion":"2018-08-20", + "endpointPrefix":"s3-control", + "protocol":"rest-xml", + "serviceFullName":"AWS S3 Control", + "serviceId":"S3 Control", + "signatureVersion":"s3v4", + "signingName":"s3", + "uid":"s3control-2018-08-20" + }, + "operations":{ + "CreateJob":{ + "name":"CreateJob", + "http":{ + "method":"POST", + "requestUri":"/v20180820/jobs" + }, + "input":{ + "shape":"CreateJobRequest", + "locationName":"CreateJobRequest", + "xmlNamespace":{"uri":"http://awss3control.amazonaws.com/doc/2018-08-20/"} + }, + "output":{"shape":"CreateJobResult"}, + "errors":[ + {"shape":"TooManyRequestsException"}, + {"shape":"BadRequestException"}, + {"shape":"IdempotencyException"}, + {"shape":"InternalServiceException"} + ], + "documentation":"

Creates an Amazon S3 batch operations job.

" + }, + "DeletePublicAccessBlock":{ + "name":"DeletePublicAccessBlock", + "http":{ + "method":"DELETE", + "requestUri":"/v20180820/configuration/publicAccessBlock" + }, + "input":{"shape":"DeletePublicAccessBlockRequest"}, + "documentation":"

Deletes the block public access configuration for the specified account.

" + }, + "DescribeJob":{ + "name":"DescribeJob", + "http":{ + "method":"GET", + "requestUri":"/v20180820/jobs/{id}" + }, + "input":{"shape":"DescribeJobRequest"}, + "output":{"shape":"DescribeJobResult"}, + "errors":[ + {"shape":"BadRequestException"}, + {"shape":"TooManyRequestsException"}, + {"shape":"NotFoundException"}, + {"shape":"InternalServiceException"} + ], + "documentation":"

Retrieves the configuration parameters and status for a batch operations job.

" + }, + "GetPublicAccessBlock":{ + "name":"GetPublicAccessBlock", + "http":{ + "method":"GET", + "requestUri":"/v20180820/configuration/publicAccessBlock" + }, + "input":{"shape":"GetPublicAccessBlockRequest"}, + "output":{"shape":"GetPublicAccessBlockOutput"}, + "errors":[ + {"shape":"NoSuchPublicAccessBlockConfiguration"} + ], + "documentation":"

" + }, + "ListJobs":{ + "name":"ListJobs", + "http":{ + "method":"GET", + "requestUri":"/v20180820/jobs" + }, + "input":{"shape":"ListJobsRequest"}, + "output":{"shape":"ListJobsResult"}, + "errors":[ + {"shape":"InvalidRequestException"}, + {"shape":"InternalServiceException"}, + {"shape":"InvalidNextTokenException"} + ], + "documentation":"

Lists current jobs and jobs that have ended within the last 30 days for the AWS account making the request.

" + }, + "PutPublicAccessBlock":{ + "name":"PutPublicAccessBlock", + "http":{ + "method":"PUT", + "requestUri":"/v20180820/configuration/publicAccessBlock" + }, + "input":{"shape":"PutPublicAccessBlockRequest"}, + "documentation":"

" + }, + "UpdateJobPriority":{ + "name":"UpdateJobPriority", + "http":{ + "method":"POST", + "requestUri":"/v20180820/jobs/{id}/priority" + }, + "input":{"shape":"UpdateJobPriorityRequest"}, + "output":{"shape":"UpdateJobPriorityResult"}, + "errors":[ + {"shape":"BadRequestException"}, + {"shape":"TooManyRequestsException"}, + {"shape":"NotFoundException"}, + {"shape":"InternalServiceException"} + ], + "documentation":"

Updates an existing job's priority.

" + }, + "UpdateJobStatus":{ + "name":"UpdateJobStatus", + "http":{ + "method":"POST", + "requestUri":"/v20180820/jobs/{id}/status" + }, + "input":{"shape":"UpdateJobStatusRequest"}, + "output":{"shape":"UpdateJobStatusResult"}, + "errors":[ + {"shape":"BadRequestException"}, + {"shape":"TooManyRequestsException"}, + {"shape":"NotFoundException"}, + {"shape":"JobStatusException"}, + {"shape":"InternalServiceException"} + ], + "documentation":"

Updates the status for the specified job. Use this operation to confirm that you want to run a job or to cancel an existing job.

" + } + }, + "shapes":{ + "AccountId":{ + "type":"string", + "max":64 + }, + "BadRequestException":{ + "type":"structure", + "members":{ + "Message":{"shape":"ExceptionMessage"} + }, + "documentation":"

", + "exception":true + }, + "Boolean":{"type":"boolean"}, + "ConfirmationRequired":{"type":"boolean"}, + "CreateJobRequest":{ + "type":"structure", + "required":[ + "AccountId", + "Operation", + "Report", + "ClientRequestToken", + "Manifest", + "Priority", + "RoleArn" + ], + "members":{ + "AccountId":{ + "shape":"AccountId", + "documentation":"

", + "location":"header", + "locationName":"x-amz-account-id" + }, + "ConfirmationRequired":{ + "shape":"ConfirmationRequired", + "documentation":"

Indicates whether confirmation is required before Amazon S3 runs the job. Confirmation is only required for jobs created through the Amazon S3 console.

", + "box":true + }, + "Operation":{ + "shape":"JobOperation", + "documentation":"

The operation that you want this job to perform on each object listed in the manifest. For more information about the available operations, see Available Operations in the Amazon Simple Storage Service Developer Guide.

" + }, + "Report":{ + "shape":"JobReport", + "documentation":"

Configuration parameters for the optional job-completion report.

" + }, + "ClientRequestToken":{ + "shape":"NonEmptyMaxLength64String", + "documentation":"

An idempotency token to ensure that you don't accidentally submit the same request twice. You can use any string up to the maximum length.

", + "idempotencyToken":true + }, + "Manifest":{ + "shape":"JobManifest", + "documentation":"

Configuration parameters for the manifest.

" + }, + "Description":{ + "shape":"NonEmptyMaxLength256String", + "documentation":"

A description for this job. You can use any string within the permitted length. Descriptions don't need to be unique and can be used for multiple jobs.

" + }, + "Priority":{ + "shape":"JobPriority", + "documentation":"

The numerical priority for this job. Higher numbers indicate higher priority.

", + "box":true + }, + "RoleArn":{ + "shape":"IAMRoleArn", + "documentation":"

The Amazon Resource Name (ARN) for the Identity and Access Management (IAM) Role that batch operations will use to execute this job's operation on each object in the manifest.

" + } + } + }, + "CreateJobResult":{ + "type":"structure", + "members":{ + "JobId":{ + "shape":"JobId", + "documentation":"

The ID for this job. Amazon S3 generates this ID automatically and returns it after a successful Create Job request.

" + } + } + }, + "DeletePublicAccessBlockRequest":{ + "type":"structure", + "required":["AccountId"], + "members":{ + "AccountId":{ + "shape":"AccountId", + "documentation":"

The account ID for the AWS account whose block public access configuration you want to delete.

", + "location":"header", + "locationName":"x-amz-account-id" + } + } + }, + "DescribeJobRequest":{ + "type":"structure", + "required":[ + "AccountId", + "JobId" + ], + "members":{ + "AccountId":{ + "shape":"AccountId", + "documentation":"

", + "location":"header", + "locationName":"x-amz-account-id" + }, + "JobId":{ + "shape":"JobId", + "documentation":"

The ID for the job whose information you want to retrieve.

", + "location":"uri", + "locationName":"id" + } + } + }, + "DescribeJobResult":{ + "type":"structure", + "members":{ + "Job":{ + "shape":"JobDescriptor", + "documentation":"

Contains the configuration parameters and status for the job specified in the Describe Job request.

" + } + } + }, + "ExceptionMessage":{ + "type":"string", + "max":1024, + "min":1 + }, + "GetPublicAccessBlockOutput":{ + "type":"structure", + "members":{ + "PublicAccessBlockConfiguration":{ + "shape":"PublicAccessBlockConfiguration", + "documentation":"

" + } + }, + "payload":"PublicAccessBlockConfiguration" + }, + "GetPublicAccessBlockRequest":{ + "type":"structure", + "required":["AccountId"], + "members":{ + "AccountId":{ + "shape":"AccountId", + "documentation":"

", + "location":"header", + "locationName":"x-amz-account-id" + } + } + }, + "IAMRoleArn":{ + "type":"string", + "max":2048, + "min":1 + }, + "IdempotencyException":{ + "type":"structure", + "members":{ + "Message":{"shape":"ExceptionMessage"} + }, + "documentation":"

", + "exception":true + }, + "InternalServiceException":{ + "type":"structure", + "members":{ + "Message":{"shape":"ExceptionMessage"} + }, + "documentation":"

", + "exception":true, + "fault":true + }, + "InvalidNextTokenException":{ + "type":"structure", + "members":{ + "Message":{"shape":"ExceptionMessage"} + }, + "documentation":"

", + "exception":true + }, + "InvalidRequestException":{ + "type":"structure", + "members":{ + "Message":{"shape":"ExceptionMessage"} + }, + "documentation":"

", + "exception":true + }, + "JobArn":{ + "type":"string", + "max":1024, + "min":1 + }, + "JobCreationTime":{"type":"timestamp"}, + "JobDescriptor":{ + "type":"structure", + "members":{ + "JobId":{ + "shape":"JobId", + "documentation":"

The ID for the specified job.

" + }, + "ConfirmationRequired":{ + "shape":"ConfirmationRequired", + "documentation":"

Indicates whether confirmation is required before Amazon S3 begins running the specified job. Confirmation is required only for jobs created through the Amazon S3 console.

", + "box":true + }, + "Description":{ + "shape":"NonEmptyMaxLength256String", + "documentation":"

The description for this job, if one was provided in this job's Create Job request.

", + "box":true + }, + "JobArn":{ + "shape":"JobArn", + "documentation":"

The Amazon Resource Name (ARN) for this job.

", + "box":true + }, + "Status":{ + "shape":"JobStatus", + "documentation":"

The current status of the specified job.

" + }, + "Manifest":{ + "shape":"JobManifest", + "documentation":"

The configuration information for the specified job's manifest object.

", + "box":true + }, + "Operation":{ + "shape":"JobOperation", + "documentation":"

The operation that the specified job is configured to execute on the objects listed in the manifest.

", + "box":true + }, + "Priority":{ + "shape":"JobPriority", + "documentation":"

The priority of the specified job.

" + }, + "ProgressSummary":{ + "shape":"JobProgressSummary", + "documentation":"

Describes the total number of tasks that the specified job has executed, the number of tasks that succeeded, and the number of tasks that failed.

", + "box":true + }, + "StatusUpdateReason":{ + "shape":"JobStatusUpdateReason", + "documentation":"

", + "box":true + }, + "FailureReasons":{ + "shape":"JobFailureList", + "documentation":"

If the specified job failed, this field contains information describing the failure.

", + "box":true + }, + "Report":{ + "shape":"JobReport", + "documentation":"

Contains the configuration information for the job-completion report if you requested one in the Create Job request.

", + "box":true + }, + "CreationTime":{ + "shape":"JobCreationTime", + "documentation":"

A timestamp indicating when this job was created.

" + }, + "TerminationDate":{ + "shape":"JobTerminationDate", + "documentation":"

A timestamp indicating when this job terminated. A job's termination date is the date and time when it succeeded, failed, or was canceled.

", + "box":true + }, + "RoleArn":{ + "shape":"IAMRoleArn", + "documentation":"

The Amazon Resource Name (ARN) for the Identity and Access Management (IAM) Role assigned to execute the tasks for this job.

", + "box":true + }, + "SuspendedDate":{ + "shape":"SuspendedDate", + "documentation":"

The timestamp when this job was suspended, if it has been suspended.

", + "box":true + }, + "SuspendedCause":{ + "shape":"SuspendedCause", + "documentation":"

The reason why the specified job was suspended. A job is only suspended if you create it through the Amazon S3 console. When you create the job, it enters the Suspended state to await confirmation before running. After you confirm the job, it automatically exits the Suspended state.

", + "box":true + } + }, + "documentation":"

A container element for the job configuration and status information returned by a Describe Job request.

" + }, + "JobFailure":{ + "type":"structure", + "members":{ + "FailureCode":{ + "shape":"JobFailureCode", + "documentation":"

The failure code, if any, for the specified job.

" + }, + "FailureReason":{ + "shape":"JobFailureReason", + "documentation":"

The failure reason, if any, for the specified job.

" + } + }, + "documentation":"

If this job failed, this element indicates why the job failed.

" + }, + "JobFailureCode":{ + "type":"string", + "max":64, + "min":1 + }, + "JobFailureList":{ + "type":"list", + "member":{"shape":"JobFailure"} + }, + "JobFailureReason":{ + "type":"string", + "max":256, + "min":1 + }, + "JobId":{ + "type":"string", + "max":36, + "min":5 + }, + "JobListDescriptor":{ + "type":"structure", + "members":{ + "JobId":{ + "shape":"JobId", + "documentation":"

The ID for the specified job.

" + }, + "Description":{ + "shape":"NonEmptyMaxLength256String", + "documentation":"

The user-specified description that was included in the specified job's Create Job request.

" + }, + "Operation":{ + "shape":"OperationName", + "documentation":"

The operation that the specified job is configured to run on each object listed in the manifest.

" + }, + "Priority":{ + "shape":"JobPriority", + "documentation":"

The current priority for the specified job.

" + }, + "Status":{ + "shape":"JobStatus", + "documentation":"

The specified job's current status.

" + }, + "CreationTime":{ + "shape":"JobCreationTime", + "documentation":"

A timestamp indicating when the specified job was created.

" + }, + "TerminationDate":{ + "shape":"JobTerminationDate", + "documentation":"

A timestamp indicating when the specified job terminated. A job's termination date is the date and time when it succeeded, failed, or was canceled.

" + }, + "ProgressSummary":{ + "shape":"JobProgressSummary", + "documentation":"

Describes the total number of tasks that the specified job has executed, the number of tasks that succeeded, and the number of tasks that failed.

" + } + }, + "documentation":"

Contains the configuration and status information for a single job retrieved as part of a job list.

" + }, + "JobListDescriptorList":{ + "type":"list", + "member":{"shape":"JobListDescriptor"} + }, + "JobManifest":{ + "type":"structure", + "required":[ + "Spec", + "Location" + ], + "members":{ + "Spec":{ + "shape":"JobManifestSpec", + "documentation":"

Describes the format of the specified job's manifest. If the manifest is in CSV format, also describes the columns contained within the manifest.

" + }, + "Location":{ + "shape":"JobManifestLocation", + "documentation":"

Contains the information required to locate the specified job's manifest.

" + } + }, + "documentation":"

Contains the configuration information for a job's manifest.

" + }, + "JobManifestFieldList":{ + "type":"list", + "member":{"shape":"JobManifestFieldName"} + }, + "JobManifestFieldName":{ + "type":"string", + "enum":[ + "Ignore", + "Bucket", + "Key", + "VersionId" + ] + }, + "JobManifestFormat":{ + "type":"string", + "enum":[ + "S3BatchOperations_CSV_20180820", + "S3InventoryReport_CSV_20161130" + ] + }, + "JobManifestLocation":{ + "type":"structure", + "required":[ + "ObjectArn", + "ETag" + ], + "members":{ + "ObjectArn":{ + "shape":"S3KeyArnString", + "documentation":"

The Amazon Resource Name (ARN) for a manifest object.

" + }, + "ObjectVersionId":{ + "shape":"S3ObjectVersionId", + "documentation":"

The optional version ID to identify a specific version of the manifest object.

", + "box":true + }, + "ETag":{ + "shape":"NonEmptyMaxLength1024String", + "documentation":"

The ETag for the specified manifest object.

" + } + }, + "documentation":"

Contains the information required to locate a manifest object.

" + }, + "JobManifestSpec":{ + "type":"structure", + "required":["Format"], + "members":{ + "Format":{ + "shape":"JobManifestFormat", + "documentation":"

Indicates which of the available formats the specified manifest uses.

" + }, + "Fields":{ + "shape":"JobManifestFieldList", + "documentation":"

If the specified manifest object is in the S3BatchOperations_CSV_20180820 format, this element describes which columns contain the required data.

", + "box":true + } + }, + "documentation":"

Describes the format of a manifest. If the manifest is in CSV format, also describes the columns contained within the manifest.

" + }, + "JobNumberOfTasksFailed":{ + "type":"long", + "min":0 + }, + "JobNumberOfTasksSucceeded":{ + "type":"long", + "min":0 + }, + "JobOperation":{ + "type":"structure", + "members":{ + "LambdaInvoke":{ + "shape":"LambdaInvokeOperation", + "documentation":"

Directs the specified job to invoke an AWS Lambda function on each object in the manifest.

", + "box":true + }, + "S3PutObjectCopy":{ + "shape":"S3CopyObjectOperation", + "documentation":"

Directs the specified job to execute a PUT Copy object call on each object in the manifest.

", + "box":true + }, + "S3PutObjectAcl":{ + "shape":"S3SetObjectAclOperation", + "documentation":"

Directs the specified job to execute a PUT Object acl call on each object in the manifest.

", + "box":true + }, + "S3PutObjectTagging":{ + "shape":"S3SetObjectTaggingOperation", + "documentation":"

Directs the specified job to execute a PUT Object tagging call on each object in the manifest.

", + "box":true + }, + "S3InitiateRestoreObject":{ + "shape":"S3InitiateRestoreObjectOperation", + "documentation":"

Directs the specified job to execute an Initiate Glacier Restore call on each object in the manifest.

", + "box":true + } + }, + "documentation":"

The operation that you want this job to perform on each object listed in the manifest. For more information about the available operations, see Available Operations in the Amazon Simple Storage Service Developer Guide.

" + }, + "JobPriority":{ + "type":"integer", + "max":2147483647, + "min":0 + }, + "JobProgressSummary":{ + "type":"structure", + "members":{ + "TotalNumberOfTasks":{ + "shape":"JobTotalNumberOfTasks", + "documentation":"

", + "box":true + }, + "NumberOfTasksSucceeded":{ + "shape":"JobNumberOfTasksSucceeded", + "documentation":"

", + "box":true + }, + "NumberOfTasksFailed":{ + "shape":"JobNumberOfTasksFailed", + "documentation":"

", + "box":true + } + }, + "documentation":"

Describes the total number of tasks that the specified job has executed, the number of tasks that succeeded, and the number of tasks that failed.

" + }, + "JobReport":{ + "type":"structure", + "required":["Enabled"], + "members":{ + "Bucket":{ + "shape":"S3BucketArnString", + "documentation":"

The bucket where specified job-completion report will be stored.

", + "box":true + }, + "Format":{ + "shape":"JobReportFormat", + "documentation":"

The format of the specified job-completion report.

", + "box":true + }, + "Enabled":{ + "shape":"Boolean", + "documentation":"

Indicates whether the specified job will generate a job-completion report.

" + }, + "Prefix":{ + "shape":"ReportPrefixString", + "documentation":"

An optional prefix to describe where in the specified bucket the job-completion report will be stored. Amazon S3 will store the job-completion report at <prefix>/job-<job-id>/report.json.

", + "box":true + }, + "ReportScope":{ + "shape":"JobReportScope", + "documentation":"

Indicates whether the job-completion report will include details of all tasks or only failed tasks.

", + "box":true + } + }, + "documentation":"

Contains the configuration parameters for a job-completion report.

" + }, + "JobReportFormat":{ + "type":"string", + "enum":["Report_CSV_20180820"] + }, + "JobReportScope":{ + "type":"string", + "enum":[ + "AllTasks", + "FailedTasksOnly" + ] + }, + "JobStatus":{ + "type":"string", + "enum":[ + "Active", + "Cancelled", + "Cancelling", + "Complete", + "Completing", + "Failed", + "Failing", + "New", + "Paused", + "Pausing", + "Preparing", + "Ready", + "Suspended" + ] + }, + "JobStatusException":{ + "type":"structure", + "members":{ + "Message":{"shape":"ExceptionMessage"} + }, + "documentation":"

", + "exception":true + }, + "JobStatusList":{ + "type":"list", + "member":{"shape":"JobStatus"} + }, + "JobStatusUpdateReason":{ + "type":"string", + "max":256, + "min":1 + }, + "JobTerminationDate":{"type":"timestamp"}, + "JobTotalNumberOfTasks":{ + "type":"long", + "min":0 + }, + "KmsKeyArnString":{ + "type":"string", + "max":2000, + "min":1 + }, + "LambdaInvokeOperation":{ + "type":"structure", + "members":{ + "FunctionArn":{ + "shape":"NonEmptyMaxLength1024String", + "documentation":"

The Amazon Resource Name (ARN) for the AWS Lambda function that the specified job will invoke for each object in the manifest.

" + } + }, + "documentation":"

Contains the configuration parameters for a Lambda Invoke operation.

" + }, + "ListJobsRequest":{ + "type":"structure", + "required":["AccountId"], + "members":{ + "AccountId":{ + "shape":"AccountId", + "documentation":"

", + "location":"header", + "locationName":"x-amz-account-id" + }, + "JobStatuses":{ + "shape":"JobStatusList", + "documentation":"

The List Jobs request returns jobs that match the statuses listed in this element.

", + "location":"querystring", + "locationName":"jobStatuses" + }, + "NextToken":{ + "shape":"NonEmptyMaxLength1024String", + "documentation":"

A pagination token to request the next page of results. Use the token that Amazon S3 returned in the NextToken element of the ListJobsResult from the previous List Jobs request.

", + "location":"querystring", + "locationName":"nextToken" + }, + "MaxResults":{ + "shape":"MaxResults", + "documentation":"

The maximum number of jobs that Amazon S3 will include in the List Jobs response. If there are more jobs than this number, the response will include a pagination token in the NextToken field to enable you to retrieve the next page of results.

", + "box":true, + "location":"querystring", + "locationName":"maxResults" + } + } + }, + "ListJobsResult":{ + "type":"structure", + "members":{ + "NextToken":{ + "shape":"NonEmptyMaxLength1024String", + "documentation":"

If the List Jobs request produced more than the maximum number of results, you can pass this value into a subsequent List Jobs request in order to retrieve the next page of results.

" + }, + "Jobs":{ + "shape":"JobListDescriptorList", + "documentation":"

The list of current jobs and jobs that have ended within the last 30 days.

" + } + } + }, + "MaxLength1024String":{ + "type":"string", + "max":1024 + }, + "MaxResults":{ + "type":"integer", + "max":1000, + "min":1 + }, + "NoSuchPublicAccessBlockConfiguration":{ + "type":"structure", + "members":{ + "Message":{"shape":"NoSuchPublicAccessBlockConfigurationMessage"} + }, + "documentation":"

", + "error":{"httpStatusCode":404}, + "exception":true + }, + "NoSuchPublicAccessBlockConfigurationMessage":{"type":"string"}, + "NonEmptyMaxLength1024String":{ + "type":"string", + "max":1024, + "min":1 + }, + "NonEmptyMaxLength2048String":{ + "type":"string", + "max":2048, + "min":1 + }, + "NonEmptyMaxLength256String":{ + "type":"string", + "max":256, + "min":1 + }, + "NonEmptyMaxLength64String":{ + "type":"string", + "max":64, + "min":1 + }, + "NotFoundException":{ + "type":"structure", + "members":{ + "Message":{"shape":"ExceptionMessage"} + }, + "documentation":"

", + "exception":true + }, + "OperationName":{ + "type":"string", + "enum":[ + "LambdaInvoke", + "S3PutObjectCopy", + "S3PutObjectAcl", + "S3PutObjectTagging", + "S3InitiateRestoreObject" + ] + }, + "PublicAccessBlockConfiguration":{ + "type":"structure", + "members":{ + "BlockPublicAcls":{ + "shape":"Setting", + "documentation":"

", + "locationName":"BlockPublicAcls" + }, + "IgnorePublicAcls":{ + "shape":"Setting", + "documentation":"

", + "locationName":"IgnorePublicAcls" + }, + "BlockPublicPolicy":{ + "shape":"Setting", + "documentation":"

", + "locationName":"BlockPublicPolicy" + }, + "RestrictPublicBuckets":{ + "shape":"Setting", + "documentation":"

", + "locationName":"RestrictPublicBuckets" + } + }, + "documentation":"

" + }, + "PutPublicAccessBlockRequest":{ + "type":"structure", + "required":[ + "PublicAccessBlockConfiguration", + "AccountId" + ], + "members":{ + "PublicAccessBlockConfiguration":{ + "shape":"PublicAccessBlockConfiguration", + "documentation":"

", + "locationName":"PublicAccessBlockConfiguration", + "xmlNamespace":{"uri":"http://awss3control.amazonaws.com/doc/2018-08-20/"} + }, + "AccountId":{ + "shape":"AccountId", + "documentation":"

", + "location":"header", + "locationName":"x-amz-account-id" + } + }, + "payload":"PublicAccessBlockConfiguration" + }, + "ReportPrefixString":{ + "type":"string", + "max":512, + "min":1 + }, + "RequestedJobStatus":{ + "type":"string", + "enum":[ + "Cancelled", + "Ready" + ] + }, + "S3AccessControlList":{ + "type":"structure", + "required":["Owner"], + "members":{ + "Owner":{ + "shape":"S3ObjectOwner", + "documentation":"

" + }, + "Grants":{ + "shape":"S3GrantList", + "documentation":"

" + } + }, + "documentation":"

" + }, + "S3AccessControlPolicy":{ + "type":"structure", + "members":{ + "AccessControlList":{ + "shape":"S3AccessControlList", + "documentation":"

", + "box":true + }, + "CannedAccessControlList":{ + "shape":"S3CannedAccessControlList", + "documentation":"

", + "box":true + } + }, + "documentation":"

" + }, + "S3BucketArnString":{ + "type":"string", + "max":128, + "min":1 + }, + "S3CannedAccessControlList":{ + "type":"string", + "enum":[ + "private", + "public-read", + "public-read-write", + "aws-exec-read", + "authenticated-read", + "bucket-owner-read", + "bucket-owner-full-control" + ] + }, + "S3ContentLength":{ + "type":"long", + "min":0 + }, + "S3CopyObjectOperation":{ + "type":"structure", + "members":{ + "TargetResource":{ + "shape":"S3BucketArnString", + "documentation":"

" + }, + "CannedAccessControlList":{ + "shape":"S3CannedAccessControlList", + "documentation":"

", + "box":true + }, + "AccessControlGrants":{ + "shape":"S3GrantList", + "documentation":"

", + "box":true + }, + "MetadataDirective":{ + "shape":"S3MetadataDirective", + "documentation":"

" + }, + "ModifiedSinceConstraint":{ + "shape":"TimeStamp", + "documentation":"

" + }, + "NewObjectMetadata":{ + "shape":"S3ObjectMetadata", + "documentation":"

" + }, + "NewObjectTagging":{ + "shape":"S3TagSet", + "documentation":"

" + }, + "RedirectLocation":{ + "shape":"NonEmptyMaxLength2048String", + "documentation":"

" + }, + "RequesterPays":{ + "shape":"Boolean", + "documentation":"

" + }, + "StorageClass":{ + "shape":"S3StorageClass", + "documentation":"

" + }, + "UnModifiedSinceConstraint":{ + "shape":"TimeStamp", + "documentation":"

" + }, + "SSEAwsKmsKeyId":{ + "shape":"KmsKeyArnString", + "documentation":"

" + }, + "TargetKeyPrefix":{"shape":"NonEmptyMaxLength1024String"}, + "ObjectLockLegalHoldStatus":{"shape":"S3ObjectLockLegalHoldStatus"}, + "ObjectLockMode":{"shape":"S3ObjectLockMode"}, + "ObjectLockRetainUntilDate":{"shape":"TimeStamp"} + }, + "documentation":"

Contains the configuration parameters for a PUT Copy object operation. Amazon S3 batch operations passes each value through to the underlying PUT Copy object API. For more information about the parameters for this operation, see PUT Object - Copy.

" + }, + "S3ExpirationInDays":{ + "type":"integer", + "min":0 + }, + "S3GlacierJobTier":{ + "type":"string", + "enum":[ + "BULK", + "STANDARD" + ] + }, + "S3Grant":{ + "type":"structure", + "members":{ + "Grantee":{ + "shape":"S3Grantee", + "documentation":"

" + }, + "Permission":{ + "shape":"S3Permission", + "documentation":"

" + } + }, + "documentation":"

" + }, + "S3GrantList":{ + "type":"list", + "member":{"shape":"S3Grant"} + }, + "S3Grantee":{ + "type":"structure", + "members":{ + "TypeIdentifier":{ + "shape":"S3GranteeTypeIdentifier", + "documentation":"

" + }, + "Identifier":{ + "shape":"NonEmptyMaxLength1024String", + "documentation":"

", + "box":true + }, + "DisplayName":{ + "shape":"NonEmptyMaxLength1024String", + "documentation":"

" + } + }, + "documentation":"

" + }, + "S3GranteeTypeIdentifier":{ + "type":"string", + "enum":[ + "id", + "emailAddress", + "uri" + ] + }, + "S3InitiateRestoreObjectOperation":{ + "type":"structure", + "members":{ + "ExpirationInDays":{ + "shape":"S3ExpirationInDays", + "documentation":"

" + }, + "GlacierJobTier":{ + "shape":"S3GlacierJobTier", + "documentation":"

" + } + }, + "documentation":"

Contains the configuration parameters for an Initiate Glacier Restore job. Amazon S3 batch operations passes each value through to the underlying POST Object restore API. For more information about the parameters for this operation, see Restoring Archives.

" + }, + "S3KeyArnString":{ + "type":"string", + "max":2000, + "min":1 + }, + "S3MetadataDirective":{ + "type":"string", + "enum":[ + "COPY", + "REPLACE" + ] + }, + "S3ObjectLockLegalHoldStatus":{ + "type":"string", + "enum":[ + "OFF", + "ON" + ] + }, + "S3ObjectLockMode":{ + "type":"string", + "enum":[ + "COMPLIANCE", + "GOVERNANCE" + ] + }, + "S3ObjectMetadata":{ + "type":"structure", + "members":{ + "CacheControl":{ + "shape":"NonEmptyMaxLength1024String", + "documentation":"

" + }, + "ContentDisposition":{ + "shape":"NonEmptyMaxLength1024String", + "documentation":"

" + }, + "ContentEncoding":{ + "shape":"NonEmptyMaxLength1024String", + "documentation":"

" + }, + "ContentLanguage":{ + "shape":"NonEmptyMaxLength1024String", + "documentation":"

" + }, + "UserMetadata":{ + "shape":"S3UserMetadata", + "documentation":"

" + }, + "ContentLength":{ + "shape":"S3ContentLength", + "documentation":"

", + "box":true + }, + "ContentMD5":{ + "shape":"NonEmptyMaxLength1024String", + "documentation":"

" + }, + "ContentType":{ + "shape":"NonEmptyMaxLength1024String", + "documentation":"

" + }, + "HttpExpiresDate":{ + "shape":"TimeStamp", + "documentation":"

" + }, + "RequesterCharged":{ + "shape":"Boolean", + "documentation":"

" + }, + "SSEAlgorithm":{ + "shape":"S3SSEAlgorithm", + "documentation":"

" + } + }, + "documentation":"

" + }, + "S3ObjectOwner":{ + "type":"structure", + "members":{ + "ID":{ + "shape":"NonEmptyMaxLength1024String", + "documentation":"

" + }, + "DisplayName":{ + "shape":"NonEmptyMaxLength1024String", + "documentation":"

" + } + }, + "documentation":"

" + }, + "S3ObjectVersionId":{ + "type":"string", + "max":2000, + "min":1 + }, + "S3Permission":{ + "type":"string", + "enum":[ + "FULL_CONTROL", + "READ", + "WRITE", + "READ_ACP", + "WRITE_ACP" + ] + }, + "S3SSEAlgorithm":{ + "type":"string", + "enum":[ + "AES256", + "KMS" + ] + }, + "S3SetObjectAclOperation":{ + "type":"structure", + "members":{ + "AccessControlPolicy":{ + "shape":"S3AccessControlPolicy", + "documentation":"

" + } + }, + "documentation":"

Contains the configuration parameters for a Set Object ACL operation. Amazon S3 batch operations passes each value through to the underlying PUT Object acl API. For more information about the parameters for this operation, see PUT Object acl.

" + }, + "S3SetObjectTaggingOperation":{ + "type":"structure", + "members":{ + "TagSet":{ + "shape":"S3TagSet", + "documentation":"

" + } + }, + "documentation":"

Contains the configuration parameters for a Set Object Tagging operation. Amazon S3 batch operations passes each value through to the underlying PUT Object tagging API. For more information about the parameters for this operation, see PUT Object tagging.

" + }, + "S3StorageClass":{ + "type":"string", + "enum":[ + "STANDARD", + "STANDARD_IA", + "ONEZONE_IA", + "GLACIER", + "INTELLIGENT_TIERING", + "DEEP_ARCHIVE" + ] + }, + "S3Tag":{ + "type":"structure", + "required":[ + "Key", + "Value" + ], + "members":{ + "Key":{ + "shape":"NonEmptyMaxLength1024String", + "documentation":"

" + }, + "Value":{ + "shape":"MaxLength1024String", + "documentation":"

" + } + }, + "documentation":"

" + }, + "S3TagSet":{ + "type":"list", + "member":{"shape":"S3Tag"} + }, + "S3UserMetadata":{ + "type":"map", + "key":{"shape":"NonEmptyMaxLength1024String"}, + "value":{"shape":"MaxLength1024String"}, + "max":8192 + }, + "Setting":{"type":"boolean"}, + "SuspendedCause":{ + "type":"string", + "max":1024, + "min":1 + }, + "SuspendedDate":{"type":"timestamp"}, + "TimeStamp":{"type":"timestamp"}, + "TooManyRequestsException":{ + "type":"structure", + "members":{ + "Message":{"shape":"ExceptionMessage"} + }, + "documentation":"

", + "exception":true + }, + "UpdateJobPriorityRequest":{ + "type":"structure", + "required":[ + "AccountId", + "JobId", + "Priority" + ], + "members":{ + "AccountId":{ + "shape":"AccountId", + "documentation":"

", + "location":"header", + "locationName":"x-amz-account-id" + }, + "JobId":{ + "shape":"JobId", + "documentation":"

The ID for the job whose priority you want to update.

", + "location":"uri", + "locationName":"id" + }, + "Priority":{ + "shape":"JobPriority", + "documentation":"

The priority you want to assign to this job.

", + "location":"querystring", + "locationName":"priority" + } + } + }, + "UpdateJobPriorityResult":{ + "type":"structure", + "required":[ + "JobId", + "Priority" + ], + "members":{ + "JobId":{ + "shape":"JobId", + "documentation":"

The ID for the job whose priority Amazon S3 updated.

" + }, + "Priority":{ + "shape":"JobPriority", + "documentation":"

The new priority assigned to the specified job.

" + } + } + }, + "UpdateJobStatusRequest":{ + "type":"structure", + "required":[ + "AccountId", + "JobId", + "RequestedJobStatus" + ], + "members":{ + "AccountId":{ + "shape":"AccountId", + "documentation":"

", + "location":"header", + "locationName":"x-amz-account-id" + }, + "JobId":{ + "shape":"JobId", + "documentation":"

The ID of the job whose status you want to update.

", + "location":"uri", + "locationName":"id" + }, + "RequestedJobStatus":{ + "shape":"RequestedJobStatus", + "documentation":"

The status that you want to move the specified job to.

", + "location":"querystring", + "locationName":"requestedJobStatus" + }, + "StatusUpdateReason":{ + "shape":"JobStatusUpdateReason", + "documentation":"

A description of the reason why you want to change the specified job's status. This field can be any string up to the maximum length.

", + "location":"querystring", + "locationName":"statusUpdateReason" + } + } + }, + "UpdateJobStatusResult":{ + "type":"structure", + "members":{ + "JobId":{ + "shape":"JobId", + "documentation":"

The ID for the job whose status was updated.

" + }, + "Status":{ + "shape":"JobStatus", + "documentation":"

The current status for the specified job.

" + }, + "StatusUpdateReason":{ + "shape":"JobStatusUpdateReason", + "documentation":"

The reason that the specified job's status was updated.

" + } + } + } + }, + "documentation":"

AWS S3 Control provides access to Amazon S3 control plane operations.

" +} diff --git a/services/s3control/src/main/resources/software/amazon/awssdk/services/s3control/execution.interceptors b/services/s3control/src/main/resources/software/amazon/awssdk/services/s3control/execution.interceptors new file mode 100644 index 000000000000..b19e9f79a356 --- /dev/null +++ b/services/s3control/src/main/resources/software/amazon/awssdk/services/s3control/execution.interceptors @@ -0,0 +1,2 @@ +software.amazon.awssdk.services.s3control.internal.interceptors.EndpointAddressInterceptor +software.amazon.awssdk.services.s3control.internal.interceptors.PayloadSigningInterceptor \ No newline at end of file diff --git a/services/s3control/src/test/java/software/amazon/awssdk/services/s3control/internal/interceptors/EndpointAddressInterceptorTest.java b/services/s3control/src/test/java/software/amazon/awssdk/services/s3control/internal/interceptors/EndpointAddressInterceptorTest.java new file mode 100644 index 000000000000..b78646701afc --- /dev/null +++ b/services/s3control/src/test/java/software/amazon/awssdk/services/s3control/internal/interceptors/EndpointAddressInterceptorTest.java @@ -0,0 +1,154 @@ +/* + * Copyright 2010-2019 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.awssdk.services.s3control.internal.interceptors; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.Optional; +import org.junit.Before; +import org.junit.Test; +import software.amazon.awssdk.core.Protocol; +import software.amazon.awssdk.core.SdkRequest; +import software.amazon.awssdk.core.async.AsyncRequestBody; +import software.amazon.awssdk.core.exception.SdkClientException; +import software.amazon.awssdk.core.interceptor.ExecutionAttributes; +import software.amazon.awssdk.core.interceptor.SdkExecutionAttribute; +import software.amazon.awssdk.core.sync.RequestBody; +import software.amazon.awssdk.http.SdkHttpFullRequest; +import software.amazon.awssdk.http.SdkHttpMethod; +import software.amazon.awssdk.http.SdkHttpRequest; +import software.amazon.awssdk.regions.Region; +import software.amazon.awssdk.services.s3control.S3ControlClient; +import software.amazon.awssdk.services.s3control.S3ControlConfiguration; + +public class EndpointAddressInterceptorTest { + + private static final String X_AMZ_ACCOUNT_ID = "x-amz-account-id"; + private static final String ACCOUNT_ID = "123456789012"; + + private SdkHttpRequest request; + + @Before + public void setup() { + request = SdkHttpFullRequest.builder() + .appendHeader(X_AMZ_ACCOUNT_ID, ACCOUNT_ID) + .protocol(Protocol.HTTPS.toString()) + .method(SdkHttpMethod.POST) + .host(S3ControlClient.serviceMetadata().endpointFor(Region.US_EAST_1).toString()) + .build(); + } + + @Test + public void modifyHttpRequest_ResolvesCorrectHost_StandardSettings() { + EndpointAddressInterceptor interceptor = new EndpointAddressInterceptor(); + SdkHttpRequest modified = interceptor.modifyHttpRequest(new Context(request), new ExecutionAttributes()); + assertThat(modified.host()).isEqualTo(ACCOUNT_ID + ".s3-control.us-east-1.amazonaws.com"); + } + + @Test + public void modifyHttpRequest_ResolvesCorrectHost_Dualstack() { + EndpointAddressInterceptor interceptor = new EndpointAddressInterceptor(); + + S3ControlConfiguration controlConfiguration = S3ControlConfiguration.builder().dualstackEnabled(true).build(); + ExecutionAttributes executionAttributes = new ExecutionAttributes(); + executionAttributes.putAttribute(SdkExecutionAttribute.SERVICE_CONFIG, controlConfiguration); + + SdkHttpRequest modified = interceptor.modifyHttpRequest(new Context(request), executionAttributes); + assertThat(modified.host()).isEqualTo(ACCOUNT_ID + ".s3-control.dualstack.us-east-1.amazonaws.com"); + } + + @Test + public void modifyHttpRequest_ResolvesCorrectHost_Fips() { + EndpointAddressInterceptor interceptor = new EndpointAddressInterceptor(); + + S3ControlConfiguration controlConfiguration = S3ControlConfiguration.builder().fipsModeEnabled(true).build(); + ExecutionAttributes executionAttributes = new ExecutionAttributes(); + executionAttributes.putAttribute(SdkExecutionAttribute.SERVICE_CONFIG, controlConfiguration); + + SdkHttpRequest modified = interceptor.modifyHttpRequest(new Context(request), executionAttributes); + assertThat(modified.host()).isEqualTo(ACCOUNT_ID + ".s3-control-fips.us-east-1.amazonaws.com"); + } + + @Test(expected = SdkClientException.class) + public void modifyHttpRequest_ThrowsException_FipsAndDualstack() { + EndpointAddressInterceptor interceptor = new EndpointAddressInterceptor(); + + S3ControlConfiguration controlConfiguration = S3ControlConfiguration.builder() + .fipsModeEnabled(true) + .dualstackEnabled(true) + .build(); + ExecutionAttributes executionAttributes = new ExecutionAttributes(); + executionAttributes.putAttribute(SdkExecutionAttribute.SERVICE_CONFIG, controlConfiguration); + + interceptor.modifyHttpRequest(new Context(request), executionAttributes); + } + + @Test(expected = SdkClientException.class) + public void modifyHttpRequest_ThrowsException_NonStandardEndpoint() { + EndpointAddressInterceptor interceptor = new EndpointAddressInterceptor(); + + S3ControlConfiguration controlConfiguration = S3ControlConfiguration.builder() + .dualstackEnabled(true) + .build(); + ExecutionAttributes executionAttributes = new ExecutionAttributes(); + executionAttributes.putAttribute(SdkExecutionAttribute.SERVICE_CONFIG, controlConfiguration); + + interceptor.modifyHttpRequest(new Context(request.toBuilder().host("some-garbage").build()), + executionAttributes); + } + + @Test(expected = SdkClientException.class) + public void modifyHttpRequest_ThrowsException_NoAccountId() { + EndpointAddressInterceptor interceptor = new EndpointAddressInterceptor(); + + S3ControlConfiguration controlConfiguration = S3ControlConfiguration.builder() + .dualstackEnabled(true) + .build(); + ExecutionAttributes executionAttributes = new ExecutionAttributes(); + executionAttributes.putAttribute(SdkExecutionAttribute.SERVICE_CONFIG, controlConfiguration); + + interceptor.modifyHttpRequest(new Context(request.toBuilder().removeHeader(X_AMZ_ACCOUNT_ID).build()), + executionAttributes); + } + + public final class Context implements software.amazon.awssdk.core.interceptor.Context.ModifyHttpRequest { + + private final SdkHttpRequest request; + + public Context(SdkHttpRequest request) { + this.request = request; + } + + @Override + public SdkRequest request() { + return null; + } + + @Override + public SdkHttpRequest httpRequest() { + return request; + } + + @Override + public Optional requestBody() { + return Optional.empty(); + } + + @Override + public Optional asyncRequestBody() { + return Optional.empty(); + } + } +} diff --git a/services/s3control/src/test/java/software/amazon/awssdk/services/s3control/internal/interceptors/PayloadSigningInterceptorTest.java b/services/s3control/src/test/java/software/amazon/awssdk/services/s3control/internal/interceptors/PayloadSigningInterceptorTest.java new file mode 100644 index 000000000000..6e0b39d1d8aa --- /dev/null +++ b/services/s3control/src/test/java/software/amazon/awssdk/services/s3control/internal/interceptors/PayloadSigningInterceptorTest.java @@ -0,0 +1,102 @@ +/* + * Copyright 2010-2019 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.awssdk.services.s3control.internal.interceptors; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.Optional; +import org.junit.Before; +import org.junit.Test; +import software.amazon.awssdk.auth.signer.S3SignerExecutionAttribute; +import software.amazon.awssdk.core.Protocol; +import software.amazon.awssdk.core.SdkRequest; +import software.amazon.awssdk.core.async.AsyncRequestBody; +import software.amazon.awssdk.core.interceptor.ExecutionAttributes; +import software.amazon.awssdk.core.sync.RequestBody; +import software.amazon.awssdk.http.SdkHttpFullRequest; +import software.amazon.awssdk.http.SdkHttpMethod; +import software.amazon.awssdk.http.SdkHttpRequest; +import software.amazon.awssdk.regions.Region; +import software.amazon.awssdk.services.s3control.S3ControlClient; + +public class PayloadSigningInterceptorTest { + + private SdkHttpRequest request; + + @Before + public void setup() { + request = SdkHttpFullRequest.builder() + .protocol(Protocol.HTTPS.toString()) + .method(SdkHttpMethod.POST) + .host(S3ControlClient.serviceMetadata().endpointFor(Region.US_EAST_1).toString()) + .build(); + } + + @Test + public void modifyHttpContent_AddsExecutionAttributeAndPayload() { + PayloadSigningInterceptor interceptor = new PayloadSigningInterceptor(); + ExecutionAttributes executionAttributes = new ExecutionAttributes(); + Optional modified = interceptor.modifyHttpContent(new Context(request, null), + executionAttributes); + + assertThat(modified.isPresent()).isTrue(); + assertThat(modified.get().contentLength()).isEqualTo(0); + assertThat(executionAttributes.getAttribute(S3SignerExecutionAttribute.ENABLE_PAYLOAD_SIGNING)).isTrue(); + } + + @Test + public void modifyHttpContent_DoesNotReplaceBody() { + PayloadSigningInterceptor interceptor = new PayloadSigningInterceptor(); + ExecutionAttributes executionAttributes = new ExecutionAttributes(); + Optional modified = interceptor.modifyHttpContent(new Context(request, RequestBody.fromString("hello")), + executionAttributes); + + assertThat(modified.isPresent()).isTrue(); + assertThat(modified.get().contentLength()).isEqualTo(5); + assertThat(executionAttributes.getAttribute(S3SignerExecutionAttribute.ENABLE_PAYLOAD_SIGNING)).isTrue(); + } + + public final class Context implements software.amazon.awssdk.core.interceptor.Context.ModifyHttpRequest { + + private final SdkHttpRequest request; + private final RequestBody requestBody; + + public Context(SdkHttpRequest request, + RequestBody requestBody) { + this.request = request; + this.requestBody = requestBody; + } + + @Override + public SdkRequest request() { + return null; + } + + @Override + public SdkHttpRequest httpRequest() { + return request; + } + + @Override + public Optional requestBody() { + return Optional.ofNullable(requestBody); + } + + @Override + public Optional asyncRequestBody() { + return Optional.empty(); + } + } +}