Allow updating S3 canned ACLs

These are simpler than the full XML API and better supported by
non-AWS S3 implementations, e.g., Ceph, S3Proxy.
This commit is contained in:
Andrew Gaul 2015-09-06 18:48:22 -07:00
parent 13701bf7ab
commit c2ba0bef32
4 changed files with 161 additions and 0 deletions

View File

@ -62,6 +62,7 @@ import org.jclouds.rest.annotations.XMLResponseParser;
import org.jclouds.s3.binders.BindACLToXMLPayload;
import org.jclouds.s3.binders.BindAsHostPrefixIfConfigured;
import org.jclouds.s3.binders.BindBucketLoggingToXmlPayload;
import org.jclouds.s3.binders.BindCannedAclToRequest;
import org.jclouds.s3.binders.BindIterableAsPayloadToDeleteRequest;
import org.jclouds.s3.binders.BindNoBucketLoggingToXmlPayload;
import org.jclouds.s3.binders.BindObjectMetadataToRequest;
@ -71,6 +72,7 @@ import org.jclouds.s3.binders.BindS3ObjectMetadataToRequest;
import org.jclouds.s3.domain.AccessControlList;
import org.jclouds.s3.domain.BucketLogging;
import org.jclouds.s3.domain.BucketMetadata;
import org.jclouds.s3.domain.CannedAccessPolicy;
import org.jclouds.s3.domain.DeleteResult;
import org.jclouds.s3.domain.ListBucketResponse;
import org.jclouds.s3.domain.ObjectMetadata;
@ -426,6 +428,28 @@ public interface S3Client extends Closeable {
BindAsHostPrefixIfConfigured.class) @ParamValidators(BucketNameValidator.class) String bucketName,
@BinderParam(BindACLToXMLPayload.class) AccessControlList acl);
/**
* Update a bucket's Access Control List settings.
* <p/>
* A PUT request operation directed at a bucket URI with the "acl" parameter sets the Access
* Control List (ACL) settings for that S3 item.
* <p />
* To set a bucket or object's ACL, you must have WRITE_ACP or FULL_CONTROL access to the item.
*
* @param bucketName
* the bucket whose Access Control List settings will be updated.
* @param acl
* the ACL to apply to the bucket.
* @return true if the bucket's Access Control List was updated successfully.
*/
@Named("UpdateBucketCannedAcl")
@PUT
@Path("/")
@QueryParams(keys = "acl")
boolean updateBucketCannedACL(@Bucket @EndpointParam(parser = AssignCorrectHostnameForBucket.class) @BinderParam(
BindAsHostPrefixIfConfigured.class) @ParamValidators(BucketNameValidator.class) String bucketName,
@BinderParam(BindCannedAclToRequest.class) CannedAccessPolicy acl);
/**
* A GET request operation directed at an object or bucket URI with the "acl" parameter retrieves
* the Access Control List (ACL) settings for that S3 item.
@ -469,6 +493,29 @@ public interface S3Client extends Closeable {
BindAsHostPrefixIfConfigured.class) @ParamValidators(BucketNameValidator.class) String bucketName,
@PathParam("key") String key, @BinderParam(BindACLToXMLPayload.class) AccessControlList acl);
/**
* Update an object's Access Control List settings.
* <p/>
* A PUT request operation directed at an object URI with the "acl" parameter sets the Access
* Control List (ACL) settings for that S3 item.
* <p />
* To set a bucket or object's ACL, you must have WRITE_ACP or FULL_CONTROL access to the item.
*
* @param bucketName
* the bucket containing the object to be updated
* @param key
* the key of the object whose Access Control List settings will be updated.
* @param acl
* the ACL to apply to the object.
* @return true if the object's Access Control List was updated successfully.
*/
@Named("UpdateObjectCannedAcl")
@PUT
@QueryParams(keys = "acl")
@Path("/{key}")
boolean updateObjectCannedACL(@Bucket @EndpointParam(parser = AssignCorrectHostnameForBucket.class) @BinderParam(
BindAsHostPrefixIfConfigured.class) @ParamValidators(BucketNameValidator.class) String bucketName,
@PathParam("key") String key, @BinderParam(BindCannedAclToRequest.class) CannedAccessPolicy acl);
/**
* A GET location request operation using a bucket URI lists the location constraint of the

View File

@ -0,0 +1,41 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License 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 org.jclouds.s3.binders;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import org.jclouds.http.HttpRequest;
import org.jclouds.rest.Binder;
import org.jclouds.s3.domain.CannedAccessPolicy;
public class BindCannedAclToRequest implements Binder {
public BindCannedAclToRequest() {
}
@SuppressWarnings("unchecked")
@Override
public <R extends HttpRequest> R bindToRequest(R request, Object input) {
checkArgument(checkNotNull(input, "input") instanceof CannedAccessPolicy, "this binder is only valid for CannedAccessPolicy!, not %s", input);
checkNotNull(request, "request");
CannedAccessPolicy policy = (CannedAccessPolicy) input;
request = (R) request.toBuilder().replaceHeader("x-amz-acl", policy.toString()).build();
return request;
}
}

View File

@ -623,4 +623,42 @@ public class S3ClientLiveTest extends BaseBlobStoreIntegrationTest {
acl.addPermission(new CanonicalUserGrantee(ownerId), Permission.WRITE_ACP);
}
public void testUpdateBucketCannedACL() throws Exception {
String containerName = getContainerName();
try {
getApi().updateBucketCannedACL(containerName, CannedAccessPolicy.PUBLIC_READ);
AccessControlList acl = getApi().getBucketACL(containerName);
assertThat(acl.hasPermission(GroupGranteeURI.ALL_USERS, Permission.READ)).isTrue();
getApi().updateBucketCannedACL(containerName, CannedAccessPolicy.PRIVATE);
acl = getApi().getBucketACL(containerName);
assertThat(acl.hasPermission(GroupGranteeURI.ALL_USERS, Permission.READ)).isFalse();
} finally {
recycleContainerAndAddToPool(containerName);
}
}
public void testUpdateObjectCannedACL() throws Exception {
String containerName = getContainerName();
try {
String key = "testUpdateObjectCannedACL";
S3Object object = getApi().newS3Object();
object.getMetadata().setKey(key);
object.setPayload(TEST_STRING);
getApi().putObject(containerName, object);
getApi().updateObjectCannedACL(containerName, key, CannedAccessPolicy.PUBLIC_READ);
AccessControlList acl = getApi().getObjectACL(containerName, key);
assertThat(acl.hasPermission(GroupGranteeURI.ALL_USERS, Permission.READ)).isTrue();
getApi().updateObjectCannedACL(containerName, key, CannedAccessPolicy.PRIVATE);
acl = getApi().getObjectACL(containerName, key);
assertThat(acl.hasPermission(GroupGranteeURI.ALL_USERS, Permission.READ)).isFalse();
object = getApi().getObject(containerName, key);
assertThat(Strings2.toStringAndClose(object.getPayload().openStream())).isEqualTo(TEST_STRING);
} finally {
returnContainer(containerName);
}
}
}

View File

@ -377,6 +377,23 @@ public abstract class S3ClientTest<T extends S3Client> extends BaseS3ClientTest<
checkFilters(request);
}
public void testUpdateBucketCannedACL() throws Exception {
Invokable<?, ?> method = method(S3Client.class, "updateBucketCannedACL", String.class, CannedAccessPolicy.class);
GeneratedHttpRequest request = processor.createRequest(method, ImmutableList.<Object> of("bucket", CannedAccessPolicy.PUBLIC_READ));
assertRequestLineEquals(request, "PUT https://bucket." + url + "/?acl HTTP/1.1");
assertNonPayloadHeadersEqual(request,
"Host: bucket." + url + "\n" +
"x-amz-acl: public-read\n");
assertPayloadEquals(request, null, "text/xml", false);
assertResponseParserClassEquals(method, request, ReturnTrueIf2xx.class);
assertSaxResponseParserClassEquals(method, null);
assertFallbackClassEquals(method, null);
checkFilters(request);
}
public void testPutBucketDefault() throws ArrayIndexOutOfBoundsException, SecurityException,
IllegalArgumentException, NoSuchMethodException, IOException {
Invokable<?, ?> method = method(S3Client.class, "putBucketInRegion", String.class, String.class,
@ -433,6 +450,24 @@ public abstract class S3ClientTest<T extends S3Client> extends BaseS3ClientTest<
checkFilters(request);
}
public void testUpdateObjectCannedACL() throws SecurityException, NoSuchMethodException, IOException {
Invokable<?, ?> method = method(S3Client.class, "updateObjectCannedACL", String.class, String.class, CannedAccessPolicy.class);
GeneratedHttpRequest request = processor.createRequest(
method, ImmutableList.<Object> of("bucket", "key", CannedAccessPolicy.PUBLIC_READ));
assertRequestLineEquals(request, "PUT https://bucket." + url + "/key?acl HTTP/1.1");
assertNonPayloadHeadersEqual(request,
"Host: bucket." + url + "\n" +
"x-amz-acl: public-read\n");
assertPayloadEquals(request, null, "text/xml", false);
assertResponseParserClassEquals(method, request, ReturnTrueIf2xx.class);
assertSaxResponseParserClassEquals(method, null);
assertFallbackClassEquals(method, null);
checkFilters(request);
}
public void testGetBucketLogging() throws SecurityException, NoSuchMethodException, IOException {
Invokable<?, ?> method = method(S3Client.class, "getBucketLogging", String.class);
GeneratedHttpRequest request = processor.createRequest(method, ImmutableList.<Object> of("bucket"));