Issue 47: Implemented PUT for setting bucket and object Access Control Lists

git-svn-id: http://jclouds.googlecode.com/svn/trunk@1431 3d8758e0-26b5-11de-8745-db77d3ebf521
This commit is contained in:
jamurty 2009-06-16 00:27:08 +00:00
parent 41be68b3a9
commit 2fb0c79e0f
13 changed files with 618 additions and 70 deletions

View File

@ -1,56 +1,70 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
$HeadURL$ $Revision$ $Date$ Copyright (C) 2009 Adrian Cole
<adrian@jclouds.org>
<!--
$HeadURL$ $Revision$ $Date$ Copyright (C) 2009 Adrian Cole
<adrian@jclouds.org>
====================================================================
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
====================================================================
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.html 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.
====================================================================
-->
http://www.apache.org/licenses/LICENSE-2.0.html 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.
====================================================================
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<parent>
<groupId>org.jclouds</groupId>
<artifactId>jclouds-s3-project</artifactId>
<version>1.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>org.jclouds</groupId>
<artifactId>jclouds-s3</artifactId>
<name>jclouds Amazon S3 Components Core</name>
<packaging>jar</packaging>
<description>jclouds Core components to access Amazon S3</description>
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<parent>
<groupId>org.jclouds</groupId>
<artifactId>jclouds-s3-project</artifactId>
<version>1.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>org.jclouds</groupId>
<artifactId>jclouds-s3</artifactId>
<name>jclouds Amazon S3 Components Core</name>
<packaging>jar</packaging>
<description>jclouds Core components to access Amazon S3</description>
<scm>
<connection>scm:svn:http://jclouds.googlecode.com/svn/trunk/s3</connection>
<developerConnection>scm:svn:https://jclouds.googlecode.com/svn/trunk/s3</developerConnection>
<url>http://jclouds.googlecode.com/svn/trunk/s3</url>
</scm>
<scm>
<connection>scm:svn:http://jclouds.googlecode.com/svn/trunk/s3</connection>
<developerConnection>scm:svn:https://jclouds.googlecode.com/svn/trunk/s3</developerConnection>
<url>http://jclouds.googlecode.com/svn/trunk/s3</url>
</scm>
<properties>
<jclouds.s3.httpstream.url>http://apache.rediris.es/maven/binaries/apache-maven-2.1.0-bin.tar.bz2
</jclouds.s3.httpstream.url>
<jclouds.s3.httpstream.md5>9268c9de2cccfd0d8fbcdbcfaf517a87</jclouds.s3.httpstream.md5>
</properties>
<dependencies>
<dependency>
<groupId>xstream</groupId>
<artifactId>xstream</artifactId>
<version>1.2</version>
<scope>test</scope>
</dependency>
</dependencies>
<properties>
<jclouds.s3.httpstream.url>http://apache.rediris.es/maven/binaries/apache-maven-2.1.0-bin.tar.bz2
</jclouds.s3.httpstream.url>
<jclouds.s3.httpstream.md5>9268c9de2cccfd0d8fbcdbcfaf517a87</jclouds.s3.httpstream.md5>
</properties>
<repositories>
<repository>
<id>googlecode.java-xmlbuilder</id>
<url>http://java-xmlbuilder.googlecode.com/svn/repo</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>xstream</groupId>
<artifactId>xstream</artifactId>
<version>1.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.jamesmurty.utils</groupId>
<artifactId>java-xmlbuilder</artifactId>
<version>0.3</version>
</dependency>
</dependencies>
</project>

View File

@ -220,10 +220,41 @@ public interface S3Connection {
*/
Future<AccessControlList> getBucketACL(String bucket);
/**
* Update a bucket's Access Control List settings.
* @param bucket
* the bucket whose Access Control List settings will be updated.
* @param acl
* the ACL to apply to the bucket. This acl object <strong>must</strong>
* include a valid owner identifier string in {@link AccessControlList#getOwner()}.
* @return
* true if the bucket's Access Control List was updated successfully.
*
* @see org.jclouds.aws.s3.commands.PutBucketAccessControlList
*/
Future<Boolean> putBucketACL(String bucket, AccessControlList acl);
/**
* @return access permissions of the object
*
* @see org.jclouds.aws.s3.commands.GetAccessControlList
*/
Future<AccessControlList> getObjectACL(String bucket, String objectKey);
/**
* Update an object's Access Control List settings.
* @param bucket
* the bucket containing the object to be updated
* @param objectKey
* the key of the object whose Access Control List settings will be updated.
* @param acl
* the ACL to apply to the object. This acl object <strong>must</strong>
* include a valid owner identifier string in {@link AccessControlList#getOwner()}.
* @return
* true if the object's Access Control List was updated successfully.
*
* @see org.jclouds.aws.s3.commands.PutBucketAccessControlList
*/
Future<Boolean> putObjectACL(String bucket, String objectKey, AccessControlList acl);
}

View File

@ -0,0 +1,72 @@
/**
*
* Copyright (C) 2009 Global Cloud Specialists, Inc. <info@globalcloudspecialists.com>
*
* ====================================================================
* 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.aws.s3.commands;
import javax.annotation.Resource;
import org.jclouds.aws.s3.domain.AccessControlList;
import org.jclouds.aws.s3.xml.AccessControlListBuilder;
import org.jclouds.http.HttpHeaders;
import org.jclouds.http.commands.callables.ReturnTrueIf2xx;
import org.jclouds.logging.Logger;
import sun.util.logging.resources.logging;
import com.google.inject.Inject;
import com.google.inject.assistedinject.Assisted;
import com.google.inject.name.Named;
/**
* 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.
*
* @see <a href="http://docs.amazonwebservices.com/AmazonS3/2006-03-01/RESTAccessPolicy.html"/>
* @author James Murty
*/
public class PutBucketAccessControlList extends S3FutureCommand<Boolean> {
@Resource
protected Logger logger = Logger.NULL;
@Inject
public PutBucketAccessControlList(@Named("jclouds.http.address") String amazonHost,
ReturnTrueIf2xx callable, @Assisted("bucketName") String bucket,
@Assisted AccessControlList acl)
{
super("PUT", "/?acl", callable, amazonHost, bucket);
String aclPayload = "";
try {
aclPayload = (new AccessControlListBuilder(acl)).getXmlString();
} catch (Exception e) {
// TODO: How do we handle this sanely?
logger.error(e, "Unable to build XML document for Access Control List: " + acl);
}
getRequest().setPayload(aclPayload);
getRequest().getHeaders().put(
HttpHeaders.CONTENT_LENGTH, aclPayload.getBytes().length + "");
}
}

View File

@ -0,0 +1,70 @@
/**
*
* Copyright (C) 2009 Global Cloud Specialists, Inc. <info@globalcloudspecialists.com>
*
* ====================================================================
* 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.aws.s3.commands;
import javax.annotation.Resource;
import org.jclouds.aws.s3.domain.AccessControlList;
import org.jclouds.aws.s3.xml.AccessControlListBuilder;
import org.jclouds.http.HttpHeaders;
import org.jclouds.http.commands.callables.ReturnTrueIf2xx;
import org.jclouds.logging.Logger;
import com.google.inject.Inject;
import com.google.inject.assistedinject.Assisted;
import com.google.inject.name.Named;
/**
* 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.
*
* @see <a href="http://docs.amazonwebservices.com/AmazonS3/2006-03-01/RESTAccessPolicy.html"/>
* @author James Murty
*/
public class PutObjectAccessControlList extends S3FutureCommand<Boolean> {
@Resource
protected Logger logger = Logger.NULL;
@Inject
public PutObjectAccessControlList(@Named("jclouds.http.address") String amazonHost,
ReturnTrueIf2xx callable, @Assisted("bucketName") String bucket,
@Assisted("key") String objectKey, @Assisted AccessControlList acl)
{
super("PUT", "/" + objectKey + "?acl", callable, amazonHost, bucket);
String aclPayload = "";
try {
aclPayload = (new AccessControlListBuilder(acl)).getXmlString();
} catch (Exception e) {
// TODO: How do we handle this sanely?
logger.error(e, "Unable to build XML document for Access Control List: " + acl);
}
getRequest().setPayload(aclPayload);
getRequest().getHeaders().put(
HttpHeaders.CONTENT_LENGTH, aclPayload.getBytes().length + "");
}
}

View File

@ -28,6 +28,7 @@ import org.jclouds.aws.s3.commands.options.GetObjectOptions;
import org.jclouds.aws.s3.commands.options.ListBucketOptions;
import org.jclouds.aws.s3.commands.options.PutBucketOptions;
import org.jclouds.aws.s3.commands.options.PutObjectOptions;
import org.jclouds.aws.s3.domain.AccessControlList;
import org.jclouds.aws.s3.domain.S3Object;
import org.jclouds.aws.s3.xml.S3ParserFactory;
@ -150,4 +151,32 @@ public class S3CommandFactory {
amazonHost, parserFactory.createAccessControlListParser(), bucket, objectKey);
}
@Inject
private PutBucketAccessControlListFactory putBucketAccessControlListFactory;
public static interface PutBucketAccessControlListFactory {
PutBucketAccessControlList create(@Assisted("bucketName") String bucket,
AccessControlList acl);
}
public PutBucketAccessControlList createPutBucketACL(String bucket, AccessControlList acl) {
return putBucketAccessControlListFactory.create(bucket, acl);
}
@Inject
private PutObjectAccessControlListFactory putObjectAccessControlListFactory;
public static interface PutObjectAccessControlListFactory {
PutObjectAccessControlList create(@Assisted("bucketName") String bucket,
@Assisted("key") String objectKey, AccessControlList acl);
}
public PutObjectAccessControlList createPutObjectACL(String bucket, String objectKey,
AccessControlList acl)
{
return putObjectAccessControlListFactory.create(bucket, objectKey, acl);
}
}

View File

@ -28,8 +28,10 @@ import org.jclouds.aws.s3.commands.DeleteBucket;
import org.jclouds.aws.s3.commands.DeleteObject;
import org.jclouds.aws.s3.commands.GetObject;
import org.jclouds.aws.s3.commands.HeadObject;
import org.jclouds.aws.s3.commands.PutBucketAccessControlList;
import org.jclouds.aws.s3.commands.PutBucket;
import org.jclouds.aws.s3.commands.PutObject;
import org.jclouds.aws.s3.commands.PutObjectAccessControlList;
import org.jclouds.aws.s3.commands.S3CommandFactory;
import com.google.inject.AbstractModule;
@ -75,6 +77,13 @@ public class S3CommandsModule extends AbstractModule {
FactoryProvider.newFactory(S3CommandFactory.HeadMetadataFactory.class,
HeadObject.class));
bind(S3CommandFactory.PutBucketAccessControlListFactory.class).toProvider(
FactoryProvider.newFactory(S3CommandFactory.PutBucketAccessControlListFactory.class,
PutBucketAccessControlList.class));
bind(S3CommandFactory.PutObjectAccessControlListFactory.class).toProvider(
FactoryProvider.newFactory(S3CommandFactory.PutObjectAccessControlListFactory.class,
PutObjectAccessControlList.class));
}
}

View File

@ -23,14 +23,17 @@
*/
package org.jclouds.aws.s3.domain;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;
import org.jclouds.aws.s3.domain.acl.CannedAccessPolicy;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.collect.Collections2;
@ -51,7 +54,7 @@ public class AccessControlList {
public static final AccessControlList NOT_FOUND = new AccessControlList();
private CanonicalUser owner;
private final SortedSet<Grant> grants = new TreeSet<Grant>();
private final List<Grant> grants = new ArrayList<Grant>();
public AccessControlList() {
}
@ -67,8 +70,8 @@ public class AccessControlList {
/**
* @return an unmodifiable set of grants represented by this ACL.
*/
public Set<Grant> getGrants() {
return Collections.unmodifiableSet(grants);
public List<Grant> getGrants() {
return Collections.unmodifiableList(grants);
}
/**
@ -280,7 +283,7 @@ public class AccessControlList {
};
public static class Grant implements Comparable<Grant> {
private final Grantee grantee;
private Grantee grantee;
private final Permission permission;
public Grant(Grantee grantee, Permission permission) {
@ -292,6 +295,11 @@ public class AccessControlList {
return grantee;
}
@VisibleForTesting
public void setGrantee(Grantee grantee) {
this.grantee = grantee;
}
public Permission getPermission() {
return permission;
}

View File

@ -36,8 +36,10 @@ import org.jclouds.aws.s3.commands.ListOwnedBuckets;
import org.jclouds.aws.s3.commands.GetObject;
import org.jclouds.aws.s3.commands.HeadObject;
import org.jclouds.aws.s3.commands.ListBucket;
import org.jclouds.aws.s3.commands.PutBucketAccessControlList;
import org.jclouds.aws.s3.commands.PutBucket;
import org.jclouds.aws.s3.commands.PutObject;
import org.jclouds.aws.s3.commands.PutObjectAccessControlList;
import org.jclouds.aws.s3.commands.S3CommandFactory;
import org.jclouds.aws.s3.commands.options.CopyObjectOptions;
import org.jclouds.aws.s3.commands.options.GetObjectOptions;
@ -253,4 +255,27 @@ public class LiveS3Connection implements S3Connection {
return getObjectACLRequest;
}
/**
* {@inheritDoc}
*
* @see PutBucketAccessControlList
*/
public Future<Boolean> putBucketACL(String bucket, AccessControlList acl) {
PutBucketAccessControlList putBucketACLRequest = factory.createPutBucketACL(bucket, acl);
client.submit(putBucketACLRequest);
return putBucketACLRequest;
}
/**
* {@inheritDoc}
*
* @see PutBucketAccessControlList
*/
public Future<Boolean> putObjectACL(String bucket, String objectKey, AccessControlList acl) {
PutObjectAccessControlList putObjectACLRequest =
factory.createPutObjectACL(bucket, objectKey, acl);
client.submit(putObjectACLRequest);
return putObjectACLRequest;
}
}

View File

@ -40,5 +40,10 @@ public interface S3Constants extends AWSConstants, S3Headers {
* time to pause before retrying a transient failure
*/
public static final String PROPERTY_S3_MAP_RETRY = "jclouds.s3.map.retry";
/**
* S3 service's XML Namespace, as used in XML request and response documents.
*/
public static final String S3_REST_API_XML_NAMESPACE = "http://s3.amazonaws.com/doc/2006-03-01/";
}

View File

@ -0,0 +1,75 @@
package org.jclouds.aws.s3.xml;
import java.util.Properties;
import javax.xml.parsers.FactoryConfigurationError;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.TransformerException;
import org.jclouds.aws.s3.domain.AccessControlList;
import org.jclouds.aws.s3.domain.AccessControlList.CanonicalUserGrantee;
import org.jclouds.aws.s3.domain.AccessControlList.EmailAddressGrantee;
import org.jclouds.aws.s3.domain.AccessControlList.Grant;
import org.jclouds.aws.s3.domain.AccessControlList.GroupGrantee;
import org.jclouds.aws.s3.reference.S3Constants;
import org.w3c.dom.Document;
import com.jamesmurty.utils.XMLBuilder;
public class AccessControlListBuilder {
private final AccessControlList acl;
public AccessControlListBuilder(AccessControlList acl) {
this.acl = acl;
}
protected XMLBuilder generateBuilder() throws ParserConfigurationException,
FactoryConfigurationError
{
XMLBuilder ownerBuilder = XMLBuilder
.create("AccessControlPolicy").attr("xmlns", S3Constants.S3_REST_API_XML_NAMESPACE)
.elem("Owner");
if (acl.getOwner() != null) {
ownerBuilder.elem("ID").text(acl.getOwner().getId()).up();
if (acl.getOwner().getDisplayName() != null) {
ownerBuilder.elem("DisplayName").text(acl.getOwner().getDisplayName()).up();
}
}
XMLBuilder grantsBuilder = ownerBuilder.root().elem("AccessControlList");
for (Grant grant : acl.getGrants()) {
XMLBuilder grantBuilder = grantsBuilder.elem("Grant");
XMLBuilder granteeBuilder = grantBuilder
.elem("Grantee").attr("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance");
if (grant.getGrantee() instanceof GroupGrantee) {
granteeBuilder.attr("xsi:type", "Group")
.elem("URI").text(grant.getGrantee().getIdentifier());
} else if (grant.getGrantee() instanceof CanonicalUserGrantee) {
CanonicalUserGrantee grantee = (CanonicalUserGrantee) grant.getGrantee();
granteeBuilder.attr("xsi:type", "CanonicalUser")
.elem("ID").text(grantee.getIdentifier()).up();
if (grantee.getDisplayName() != null) {
granteeBuilder.elem("DisplayName").text(grantee.getDisplayName());
}
} else if (grant.getGrantee() instanceof EmailAddressGrantee) {
granteeBuilder.attr("xsi:type", "AmazonCustomerByEmail")
.elem("EmailAddress").text(grant.getGrantee().getIdentifier());
}
grantBuilder.elem("Permission").text(grant.getPermission().toString());
}
return grantsBuilder;
}
public Document getDocument() throws ParserConfigurationException, FactoryConfigurationError {
return generateBuilder().getDocument();
}
public String getXmlString() throws TransformerException, ParserConfigurationException,
FactoryConfigurationError
{
Properties outputProperties = new Properties();
outputProperties.put(javax.xml.transform.OutputKeys.OMIT_XML_DECLARATION, "yes");
return generateBuilder().asString(outputProperties);
}
}

View File

@ -54,8 +54,12 @@ import org.jclouds.aws.s3.commands.options.ListBucketOptions;
import org.jclouds.aws.s3.commands.options.PutBucketOptions;
import org.jclouds.aws.s3.commands.options.PutObjectOptions;
import org.jclouds.aws.s3.domain.AccessControlList;
import org.jclouds.aws.s3.domain.CanonicalUser;
import org.jclouds.aws.s3.domain.S3Bucket;
import org.jclouds.aws.s3.domain.S3Object;
import org.jclouds.aws.s3.domain.AccessControlList.CanonicalUserGrantee;
import org.jclouds.aws.s3.domain.AccessControlList.EmailAddressGrantee;
import org.jclouds.aws.s3.domain.AccessControlList.Grant;
import org.jclouds.aws.s3.domain.S3Bucket.Metadata;
import org.jclouds.aws.s3.domain.acl.CannedAccessPolicy;
import org.jclouds.aws.s3.util.S3Utils;
@ -80,7 +84,11 @@ import com.thoughtworks.xstream.XStream;
public class StubS3Connection implements S3Connection {
private static Map<String, Map<String, S3Object>> bucketToContents = new ConcurrentHashMap<String, Map<String, S3Object>>();
private static Map<String, Metadata.LocationConstraint> bucketToLocation = new ConcurrentHashMap<String, Metadata.LocationConstraint>();
private static Map<String, CannedAccessPolicy> keyToAcl = new ConcurrentHashMap<String, CannedAccessPolicy>();
/**
* An S3 item's "ACL" may be a {@link CannedAccessPolicy} or an {@link AccessControlList}.
*/
private static Map<String, Object> keyToAcl = new ConcurrentHashMap<String, Object>();
public static final String DEFAULT_OWNER_ID = "abc123";
@ -534,17 +542,27 @@ public class StubS3Connection implements S3Connection {
}
};
}
protected AccessControlList getACLforS3Item(String bucketAndObjectKey) {
AccessControlList acl = null;
Object aclObj = keyToAcl.get(bucketAndObjectKey);
if (aclObj instanceof AccessControlList) {
acl = (AccessControlList) aclObj;
} else if (aclObj instanceof CannedAccessPolicy) {
acl = AccessControlList.fromCannedAccessPolicy(
(CannedAccessPolicy) aclObj, DEFAULT_OWNER_ID);
} else if (aclObj == null) {
// Default to private access policy
acl = AccessControlList.fromCannedAccessPolicy(
CannedAccessPolicy.PRIVATE, DEFAULT_OWNER_ID);
}
return acl;
}
public Future<AccessControlList> getBucketACL(final String bucket) {
return new FutureBase<AccessControlList>() {
public AccessControlList get() throws InterruptedException, ExecutionException {
CannedAccessPolicy cannedAP = keyToAcl.get(bucket);
if (cannedAP == null) {
// Default to private access policy
cannedAP = CannedAccessPolicy.PRIVATE;
}
return AccessControlList.fromCannedAccessPolicy(cannedAP, DEFAULT_OWNER_ID);
return getACLforS3Item(bucket);
}
};
}
@ -552,13 +570,48 @@ public class StubS3Connection implements S3Connection {
public Future<AccessControlList> getObjectACL(final String bucket, final String objectKey) {
return new FutureBase<AccessControlList>() {
public AccessControlList get() throws InterruptedException, ExecutionException {
CannedAccessPolicy cannedAP = keyToAcl.get(bucket + "/" + objectKey);
if (cannedAP == null) {
// Default to private access policy
cannedAP = CannedAccessPolicy.PRIVATE;
}
return AccessControlList.fromCannedAccessPolicy(cannedAP, DEFAULT_OWNER_ID);
return getACLforS3Item(bucket + "/" + objectKey);
}
};
}
/**
* Replace any AmazonCustomerByEmail grantees with a somewhat-arbitrary canonical user
* grantee, to match S3 which substitutes each email address grantee with that
* user's corresponding ID. In short, although you can PUT email address grantees,
* these are actually subsequently returned by S3 as canonical user grantees.
*
* @param acl
* @return
*/
protected AccessControlList sanitizeUploadedACL(AccessControlList acl) {
// Replace any email address grantees with canonical user grantees, using
// the acl's owner ID as the surrogate replacement.
for (Grant grant : acl.getGrants()) {
if (grant.getGrantee() instanceof EmailAddressGrantee) {
grant.setGrantee(new CanonicalUserGrantee(
acl.getOwner().getId(), acl.getOwner().getDisplayName()));
}
}
return acl;
}
public Future<Boolean> putBucketACL(final String bucket, final AccessControlList acl) {
return new FutureBase<Boolean>() {
public Boolean get() throws InterruptedException, ExecutionException {
keyToAcl.put(bucket, sanitizeUploadedACL(acl));
return true;
}
};
}
public Future<Boolean> putObjectACL(final String bucket, final String objectKey,
final AccessControlList acl)
{
return new FutureBase<Boolean>() {
public Boolean get() throws InterruptedException, ExecutionException {
keyToAcl.put(bucket + "/" + objectKey, sanitizeUploadedACL(acl));
return true;
}
};
}

View File

@ -0,0 +1,137 @@
/**
*
* Copyright (C) 2009 Global Cloud Specialists, Inc. <info@globalcloudspecialists.com>
*
* ====================================================================
* 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.aws.s3.commands;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertTrue;
import java.io.IOException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import org.jclouds.aws.s3.S3IntegrationTest;
import org.jclouds.aws.s3.domain.AccessControlList;
import org.jclouds.aws.s3.domain.AccessControlList.CanonicalUserGrantee;
import org.jclouds.aws.s3.domain.AccessControlList.EmailAddressGrantee;
import org.jclouds.aws.s3.domain.AccessControlList.GroupGranteeURI;
import org.jclouds.aws.s3.domain.AccessControlList.Permission;
import org.testng.annotations.Test;
/**
* Tests integrated functionality of all commands that retrieve Access Control Lists (ACLs).
*
* @author James Murty
*/
@Test(groups = {"integration", "live"}, testName = "s3.PutAccessControlListIntegrationTest")
public class PutAccessControlListIntegrationTest extends S3IntegrationTest {
@Test
void testUpdateBucketACL() throws InterruptedException, ExecutionException,
TimeoutException, IOException, Exception
{
bucketName = bucketPrefix + ".testPrivateBucketACL".toLowerCase();
// Create default (private) bucket
createBucketAndEnsureEmpty(bucketName);
// Confirm the bucket is private
AccessControlList acl = client.getBucketACL(bucketName).get(10, TimeUnit.SECONDS);
String ownerId = acl.getOwner().getId();
assertEquals(acl.getGrants().size(), 1);
assertTrue(acl.hasPermission(ownerId, Permission.FULL_CONTROL));
// Update the bucket's ACL by adding grants.
acl.addPermission(GroupGranteeURI.ALL_USERS, Permission.READ);
acl.addPermission(new EmailAddressGrantee("james@misterm.org"), Permission.READ_ACP);
acl.addPermission(new CanonicalUserGrantee(ownerId), Permission.WRITE_ACP);
assertEquals(acl.getGrants().size(), 4);
assertTrue(client.putBucketACL(bucketName, acl).get(10, TimeUnit.SECONDS));
// Confirm that the updated ACL has stuck.
acl = client.getBucketACL(bucketName).get(10, TimeUnit.SECONDS);
assertEquals(acl.getGrants().size(), 4);
assertTrue(acl.hasPermission(ownerId, Permission.FULL_CONTROL));
assertTrue(acl.hasPermission(GroupGranteeURI.ALL_USERS, Permission.READ));
assertTrue(acl.hasPermission(ownerId, Permission.WRITE_ACP));
// EmailAddressGrantee is replaced by a CanonicalUserGrantee, so we cannot test by email addr
assertTrue(acl.hasPermission(ownerId, Permission.READ_ACP));
emptyBucket(bucketName);
}
@Test
void testUpdateObjectACL() throws InterruptedException, ExecutionException,
TimeoutException, IOException
{
bucketName = bucketPrefix + ".testObjectACL".toLowerCase();
createBucketAndEnsureEmpty(bucketName);
String objectKey = "pr“vate-acl";
// Private object
addObjectToBucket(bucketName, objectKey);
AccessControlList acl = client.getObjectACL(bucketName, objectKey)
.get(10, TimeUnit.SECONDS);
String ownerId = acl.getOwner().getId();
assertEquals(acl.getGrants().size(), 1);
assertTrue(acl.hasPermission(ownerId, Permission.FULL_CONTROL));
// Update the object's ACL by adding grants.
acl.addPermission(GroupGranteeURI.ALL_USERS, Permission.READ);
acl.addPermission(new EmailAddressGrantee("james@misterm.org"), Permission.READ_ACP);
acl.addPermission(new CanonicalUserGrantee(ownerId), Permission.WRITE_ACP);
assertTrue(client.putObjectACL(bucketName, objectKey, acl).get(10, TimeUnit.SECONDS));
// Confirm that the updated ACL has stuck.
acl = client.getObjectACL(bucketName, objectKey).get(10, TimeUnit.SECONDS);
assertEquals(acl.getGrants().size(), 4);
assertTrue(acl.hasPermission(ownerId, Permission.FULL_CONTROL));
assertTrue(acl.hasPermission(GroupGranteeURI.ALL_USERS, Permission.READ));
assertTrue(acl.hasPermission(ownerId, Permission.WRITE_ACP));
// EmailAddressGrantee is replaced by a CanonicalUserGrantee, so we cannot test by email addr
assertTrue(acl.hasPermission(ownerId, Permission.READ_ACP));
/*
* Revoke all of owner's permissions!
*/
acl.revokeAllPermissions(new CanonicalUserGrantee(ownerId));
assertEquals(acl.getGrants().size(), 1);
// Only public read permission should remain...
assertTrue(acl.hasPermission(GroupGranteeURI.ALL_USERS, Permission.READ));
// Update the object's ACL settings
assertTrue(client.putObjectACL(bucketName, objectKey, acl).get(10, TimeUnit.SECONDS));
// Confirm that the updated ACL has stuck
acl = client.getObjectACL(bucketName, objectKey).get(10, TimeUnit.SECONDS);
assertEquals(acl.getGrants().size(), 1);
assertEquals(acl.getPermissions(ownerId).size(), 0);
assertTrue(acl.hasPermission(GroupGranteeURI.ALL_USERS, Permission.READ));
emptyBucket(bucketName);
}
}

View File

@ -26,13 +26,16 @@ package org.jclouds.aws.s3.xml;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertTrue;
import javax.xml.parsers.FactoryConfigurationError;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.TransformerException;
import org.apache.commons.io.IOUtils;
import org.jclouds.aws.s3.domain.AccessControlList;
import org.jclouds.aws.s3.domain.AccessControlList.GroupGranteeURI;
import org.jclouds.aws.s3.domain.AccessControlList.Permission;
import org.jclouds.http.HttpException;
import org.jclouds.http.commands.callables.xml.ParseSax;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
@Test(groups = "unit", testName = "s3.AccessControlListHandlerTest")
@ -40,7 +43,6 @@ public class AccessControlListHandlerTest extends BaseHandlerTest {
public static final String aclOwnerOnly = "<AccessControlPolicy xmlns=\"http://s3.amazonaws.com/doc/2006-03-01/\"><Owner><ID>1a405254c932b52e5b5caaa88186bc431a1bacb9ece631f835daddaf0c47677c</ID><DisplayName>jamesmurty</DisplayName></Owner><AccessControlList><Grant><Grantee xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:type=\"CanonicalUser\"><ID>1a405254c932b52e5b5caaa88186bc431a1bacb9ece631f835daddaf0c47677c</ID><DisplayName>jamesmurty</DisplayName></Grantee><Permission>FULL_CONTROL</Permission></Grant></AccessControlList></AccessControlPolicy>";
public static final String aclExtreme = "<AccessControlPolicy xmlns=\"http://s3.amazonaws.com/doc/2006-03-01/\"><Owner><ID>1a405254c932b52e5b5caaa88186bc431a1bacb9ece631f835daddaf0c47677c</ID><DisplayName>jamesmurty</DisplayName></Owner><AccessControlList><Grant><Grantee xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:type=\"Group\"><URI>http://acs.amazonaws.com/groups/global/AuthenticatedUsers</URI></Grantee><Permission>WRITE</Permission></Grant><Grant><Grantee xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:type=\"Group\"><URI>http://acs.amazonaws.com/groups/global/AuthenticatedUsers</URI></Grantee><Permission>READ_ACP</Permission></Grant><Grant><Grantee xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:type=\"CanonicalUser\"><ID>1a405254c932b52e5b5caaa88186bc431a1bacb9ece631f835daddaf0c47677c</ID><DisplayName>jamesmurty</DisplayName></Grantee><Permission>WRITE</Permission></Grant><Grant><Grantee xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:type=\"Group\"><URI>http://acs.amazonaws.com/groups/global/AuthenticatedUsers</URI></Grantee><Permission>WRITE_ACP</Permission></Grant><Grant><Grantee xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:type=\"Group\"><URI>http://acs.amazonaws.com/groups/global/AllUsers</URI></Grantee><Permission>READ</Permission></Grant><Grant><Grantee xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:type=\"Group\"><URI>http://acs.amazonaws.com/groups/global/AuthenticatedUsers</URI></Grantee><Permission>READ</Permission></Grant><Grant><Grantee xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:type=\"Group\"><URI>http://acs.amazonaws.com/groups/s3/LogDelivery</URI></Grantee><Permission>WRITE</Permission></Grant><Grant><Grantee xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:type=\"CanonicalUser\"><ID>1a405254c932b52e5b5caaa88186bc431a1bacb9ece631f835daddaf0c47677c</ID><DisplayName>jamesmurty</DisplayName></Grantee><Permission>READ</Permission></Grant><Grant><Grantee xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:type=\"CanonicalUser\"><ID>1a405254c932b52e5b5caaa88186bc431a1bacb9ece631f835daddaf0c47677c</ID><DisplayName>jamesmurty</DisplayName></Grantee><Permission>FULL_CONTROL</Permission></Grant></AccessControlList></AccessControlPolicy>";
@BeforeMethod
ParseSax<AccessControlList> createParser() {
ParseSax<AccessControlList> parser = parserFactory.createAccessControlListParser();
return parser;
@ -80,5 +82,23 @@ public class AccessControlListHandlerTest extends BaseHandlerTest {
assertTrue(acl.hasPermission(GroupGranteeURI.AUTHENTICATED_USERS, Permission.WRITE_ACP));
assertTrue(acl.hasPermission(GroupGranteeURI.LOG_DELIVERY, Permission.WRITE));
}
@Test
public void testRoundTripParseAndFormat() throws HttpException, TransformerException,
ParserConfigurationException, FactoryConfigurationError
{
AccessControlList parsedAcl;
String formattedAcl;
parsedAcl = createParser().parse(
IOUtils.toInputStream(aclOwnerOnly));
formattedAcl = new AccessControlListBuilder(parsedAcl).getXmlString();
assertEquals(formattedAcl, aclOwnerOnly);
parsedAcl = createParser().parse(
IOUtils.toInputStream(aclExtreme));
formattedAcl = new AccessControlListBuilder(parsedAcl).getXmlString();
assertEquals(formattedAcl, aclExtreme);
}
}