mirror of https://github.com/apache/jclouds.git
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:
parent
41be68b3a9
commit
2fb0c79e0f
|
@ -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>
|
||||
|
|
|
@ -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);
|
||||
|
||||
}
|
||||
|
|
|
@ -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 + "");
|
||||
}
|
||||
|
||||
}
|
|
@ -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 + "");
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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));
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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/";
|
||||
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue