From 19e2426220ca467f63f69a7363e0d7ced5713718 Mon Sep 17 00:00:00 2001 From: Andrew Gaul Date: Mon, 18 Jan 2016 12:04:43 -0800 Subject: [PATCH] Map a subset of XML ACLs to canned ACLs Fixes #116. --- pom.xml | 5 ++ .../org/gaul/s3proxy/AccessControlPolicy.java | 64 +++++++++++++++++++ .../java/org/gaul/s3proxy/S3ProxyHandler.java | 45 ++++++++++++- src/main/resources/checkstyle.xml | 2 + .../java/org/gaul/s3proxy/S3AwsSdkTest.java | 23 +++++-- 5 files changed, 130 insertions(+), 9 deletions(-) create mode 100644 src/main/java/org/gaul/s3proxy/AccessControlPolicy.java diff --git a/pom.xml b/pom.xml index d112289..b9afcb0 100644 --- a/pom.xml +++ b/pom.xml @@ -301,6 +301,11 @@ 4.12 test + + com.fasterxml.jackson.dataformat + jackson-dataformat-xml + 2.7.0 + commons-fileupload commons-fileupload diff --git a/src/main/java/org/gaul/s3proxy/AccessControlPolicy.java b/src/main/java/org/gaul/s3proxy/AccessControlPolicy.java new file mode 100644 index 0000000..4b3c12e --- /dev/null +++ b/src/main/java/org/gaul/s3proxy/AccessControlPolicy.java @@ -0,0 +1,64 @@ +/* + * Copyright 2014-2016 Andrew Gaul + * + * Licensed 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.gaul.s3proxy; + +import java.util.Collection; + +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty; + +/** Represent an Amazon AccessControlPolicy for a container or object. */ +// CHECKSTYLE:OFF +final class AccessControlPolicy { + @JacksonXmlProperty(localName = "Owner") + Owner owner; + @JacksonXmlProperty(localName = "AccessControlList") + AccessControlList aclList; + + static final class Owner { + @JacksonXmlProperty(localName = "ID") + String id; + @JacksonXmlProperty(localName = "DisplayName") + String displayName; + } + + static final class AccessControlList { + @JacksonXmlProperty(localName = "Grant") + @JacksonXmlElementWrapper(useWrapping = false) + Collection grants; + + static final class Grant { + @JacksonXmlProperty(localName = "Grantee") + Grantee grantee; + @JacksonXmlProperty(localName = "Permission") + String permission; + + static final class Grantee { + @JacksonXmlProperty(namespace = "xsi", localName = "type", + isAttribute = true) + String type; + @JacksonXmlProperty(localName = "ID") + String id; + @JacksonXmlProperty(localName = "DisplayName") + String displayName; + @JacksonXmlProperty(localName = "URI") + String uri; + } + } + } +} +// CHECKSTYLE:ON diff --git a/src/main/java/org/gaul/s3proxy/S3ProxyHandler.java b/src/main/java/org/gaul/s3proxy/S3ProxyHandler.java index f91f640..7813ece 100644 --- a/src/main/java/org/gaul/s3proxy/S3ProxyHandler.java +++ b/src/main/java/org/gaul/s3proxy/S3ProxyHandler.java @@ -58,6 +58,7 @@ import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamReader; import javax.xml.stream.XMLStreamWriter; +import com.fasterxml.jackson.dataformat.xml.XmlMapper; import com.google.common.base.Joiner; import com.google.common.base.Objects; import com.google.common.base.Optional; @@ -841,15 +842,53 @@ final class S3ProxyHandler extends AbstractHandler { return; } - // TODO: how to handle XML ACLs? - int ch = is.read(); + PushbackInputStream pis = new PushbackInputStream(is); + int ch = pis.read(); if (ch != -1) { - throw new S3Exception(S3ErrorCode.NOT_IMPLEMENTED); + pis.unread(ch); + AccessControlPolicy policy = new XmlMapper().readValue( + pis, AccessControlPolicy.class); + access = mapXmlAclsToCannedPolicy(policy); } blobStore.setBlobAccess(containerName, blobName, access); } + /** Map XML ACLs to a canned policy if an exact tranformation exists. */ + private static BlobAccess mapXmlAclsToCannedPolicy( + AccessControlPolicy policy) throws S3Exception { + if (!policy.owner.id.equals(FAKE_OWNER_ID)) { + throw new S3Exception(S3ErrorCode.NOT_IMPLEMENTED); + } + + boolean ownerFullControl = false; + boolean allUsersRead = false; + for (AccessControlPolicy.AccessControlList.Grant grant : + policy.aclList.grants) { + if (grant.grantee.type.equals("CanonicalUser") && + grant.grantee.id.equals(FAKE_OWNER_ID) && + grant.permission.equals("FULL_CONTROL")) { + ownerFullControl = true; + } else if (grant.grantee.type.equals("Group") && + grant.grantee.uri.equals("http://acs.amazonaws.com/" + + "groups/global/AllUsers") && + grant.permission.equals("READ")) { + allUsersRead = true; + } else { + throw new S3Exception(S3ErrorCode.NOT_IMPLEMENTED); + } + } + + if (ownerFullControl) { + if (allUsersRead) { + return BlobAccess.PUBLIC_READ; + } + return BlobAccess.PRIVATE; + } else { + throw new S3Exception(S3ErrorCode.NOT_IMPLEMENTED); + } + } + private void handleContainerList(HttpServletResponse response, BlobStore blobStore) throws IOException { PageSet buckets = blobStore.list(); diff --git a/src/main/resources/checkstyle.xml b/src/main/resources/checkstyle.xml index 9b7826d..8071479 100644 --- a/src/main/resources/checkstyle.xml +++ b/src/main/resources/checkstyle.xml @@ -9,6 +9,7 @@ + @@ -37,6 +38,7 @@ +