You are viewing a plain text version of this content. The canonical link for it is here.
Posted to issues@ozone.apache.org by GitBox <gi...@apache.org> on 2021/04/13 17:08:32 UTC

[GitHub] [ozone] xiaoyuyao commented on a change in pull request #1701: HDDS-4585. Support bucket acl operation in S3g

xiaoyuyao commented on a change in pull request #1701:
URL: https://github.com/apache/ozone/pull/1701#discussion_r612630356



##########
File path: hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/endpoint/BucketEndpoint.java
##########
@@ -353,6 +373,204 @@ public MultiDeleteResponse multiDelete(@PathParam("bucket") String bucketName,
     return result;
   }
 
+  /**
+   * Implement acl get.
+   * <p>
+   * see: https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetBucketAcl.html
+   */
+  public S3BucketAcl getAcl(String bucketName)
+      throws OS3Exception, IOException {
+    S3BucketAcl result = new S3BucketAcl();
+    try {
+      OzoneBucket bucket = getBucket(bucketName);
+      OzoneVolume volume = getVolume();
+      // TODO: use bucket owner instead of volume owner here once bucket owner
+      // TODO: is supported.
+      S3Owner owner = new S3Owner(volume.getOwner(), volume.getOwner());
+      result.setOwner(owner);
+
+      // TODO: remove this duplication avoid logic when ACCESS and DEFAULT scope
+      // TODO: are merged.
+      // Use set to remove ACLs with different scopes(ACCESS and DEFAULT)
+      Set<Grant> grantSet = new HashSet<>();
+      // Return ACL list
+      for (OzoneAcl acl : bucket.getAcls()) {
+        List<Grant> grants = S3Acl.ozoneNativeAclToS3Acl(acl);
+        grantSet.addAll(grants);
+      }
+      ArrayList<Grant> grantList = new ArrayList<>();
+      grantList.addAll(grantSet);
+      result.setAclList(
+          new S3BucketAcl.AccessControlList(grantList));
+      return result;
+    } catch (OMException ex) {
+      if (ex.getResult() == ResultCodes.BUCKET_NOT_FOUND) {
+        throw S3ErrorTable.newError(S3ErrorTable
+            .NO_SUCH_BUCKET, bucketName);
+      } else if (ex.getResult() == ResultCodes.PERMISSION_DENIED) {
+        throw S3ErrorTable.newError(S3ErrorTable
+            .ACCESS_DENIED, bucketName);
+      } else {
+        LOG.error("Failed to get acl of Bucket " + bucketName, ex);
+        throw S3ErrorTable.newError(S3ErrorTable.INTERNAL_ERROR, bucketName);
+      }
+    }
+  }
+
+  /**
+   * Implement acl put.
+   * <p>
+   * see: https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutBucketAcl.html
+   */
+  public Response putAcl(String bucketName, HttpHeaders httpHeaders,
+      InputStream body) throws IOException, OS3Exception {
+    String grantReads = httpHeaders.getHeaderString(S3Acl.GRANT_READ);
+    String grantWrites = httpHeaders.getHeaderString(S3Acl.GRANT_WRITE);
+    String grantReadACP = httpHeaders.getHeaderString(S3Acl.GRANT_READ_CAP);
+    String grantWriteACP = httpHeaders.getHeaderString(S3Acl.GRANT_WRITE_CAP);
+    String grantFull = httpHeaders.getHeaderString(S3Acl.GRANT_FULL_CONTROL);
+
+    try {
+      OzoneBucket bucket = getBucket(bucketName);
+      OzoneVolume volume = getVolume();
+
+      List<OzoneAcl> ozoneAclListOnBucket = new ArrayList<>();
+      List<OzoneAcl> ozoneAclListOnVolume = new ArrayList<>();
+
+      if (grantReads == null && grantWrites == null && grantReadACP == null
+          && grantWriteACP == null && grantFull == null) {
+        S3BucketAcl putBucketAclRequest =
+            new PutBucketAclRequestUnmarshaller().readFrom(
+            null, null, null, null, null, body);
+        // Handle grants in body
+        ozoneAclListOnBucket.addAll(
+            S3Acl.s3AclToOzoneNativeAclOnBucket(putBucketAclRequest));
+        ozoneAclListOnVolume.addAll(
+            S3Acl.s3AclToOzoneNativeAclOnVolume(putBucketAclRequest));
+      } else {
+
+        // Handle grants in headers
+        if (grantReads != null) {
+          ozoneAclListOnBucket.addAll(getAndConvertAclOnBucket(grantReads,
+              S3Acl.ACLType.READ.getValue()));
+          ozoneAclListOnVolume.addAll(getAndConvertAclOnVolume(grantReads,
+              S3Acl.ACLType.READ.getValue()));
+        }
+        if (grantWrites != null) {
+          ozoneAclListOnBucket.addAll(getAndConvertAclOnBucket(grantWrites,
+              S3Acl.ACLType.WRITE.getValue()));
+          ozoneAclListOnVolume.addAll(getAndConvertAclOnVolume(grantWrites,
+              S3Acl.ACLType.WRITE.getValue()));
+        }
+        if (grantReadACP != null) {
+          ozoneAclListOnBucket.addAll(getAndConvertAclOnBucket(grantReadACP,
+              S3Acl.ACLType.READ_ACP.getValue()));
+          ozoneAclListOnVolume.addAll(getAndConvertAclOnVolume(grantReadACP,
+              S3Acl.ACLType.READ_ACP.getValue()));
+        }
+        if (grantWriteACP != null) {
+          ozoneAclListOnBucket.addAll(getAndConvertAclOnBucket(grantWriteACP,
+              S3Acl.ACLType.WRITE_ACP.getValue()));
+          ozoneAclListOnVolume.addAll(getAndConvertAclOnVolume(grantWriteACP,
+              S3Acl.ACLType.WRITE_ACP.getValue()));
+        }
+        if (grantFull != null) {
+          ozoneAclListOnBucket.addAll(getAndConvertAclOnBucket(grantFull,
+              S3Acl.ACLType.FULL_CONTROL.getValue()));
+          ozoneAclListOnVolume.addAll(getAndConvertAclOnVolume(grantFull,
+              S3Acl.ACLType.FULL_CONTROL.getValue()));
+        }
+      }
+
+      // A put request will reset all previous ACLs
+      bucket.setAcl(ozoneAclListOnBucket);
+      volume.setAcl(ozoneAclListOnVolume);
+    } catch (OMException exception) {
+      LOG.error("Error in set ACL Request for bucket: {}", bucketName,
+          exception);
+      if (exception.getResult() == ResultCodes.BUCKET_NOT_FOUND) {
+        throw S3ErrorTable.newError(S3ErrorTable.NO_SUCH_BUCKET,
+            bucketName);
+      } else if (exception.getResult() == ResultCodes.PERMISSION_DENIED) {
+        throw S3ErrorTable.newError(S3ErrorTable
+            .ACCESS_DENIED, bucketName);
+      }
+      throw exception;
+    }
+    return Response.status(HttpStatus.SC_OK).build();
+  }
+
+  /**
+   *  Example: x-amz-grant-write: \
+   *  uri="http://acs.amazonaws.com/groups/s3/LogDelivery", id="111122223333", \
+   *  id="555566667777".
+   */
+  private List<OzoneAcl> getAndConvertAclOnBucket(String value,
+      String permission) throws OS3Exception {
+    List<OzoneAcl> ozoneAclList = new ArrayList<>();
+    if (StringUtils.isEmpty(value)) {
+      return ozoneAclList;
+    }
+    String[] subValues = value.split(",");
+    for (String acl: subValues) {
+      String[] part = acl.split("=");
+      if (part.length != 2) {
+        throw S3ErrorTable.newError(S3ErrorTable.INVALID_ARGUMENT, acl);
+      }
+      S3Acl.ACLIdentityType type =
+          S3Acl.ACLIdentityType.getTypeFromHeaderType(part[0]);
+      if (type == null || !type.isSupported()) {
+        LOG.warn("S3 grantee {} is null or not supported", part[0]);
+        throw S3ErrorTable.newError(NOT_IMPLEMENTED, part[0]);
+      }
+      // Build ACL on Bucket
+      BitSet aclsOnBucket =
+          S3Acl.getOzoneAclOnBucketFromS3Permission(permission);
+      OzoneAcl defaultOzoneAcl = new OzoneAcl(
+          IAccessAuthorizer.ACLIdentityType.USER, part[1], aclsOnBucket,
+          OzoneAcl.AclScope.DEFAULT);
+      OzoneAcl accessOzoneAcl = new OzoneAcl(
+          IAccessAuthorizer.ACLIdentityType.USER, part[1], aclsOnBucket,
+          OzoneAcl.AclScope.ACCESS);
+      ozoneAclList.add(defaultOzoneAcl);
+      ozoneAclList.add(accessOzoneAcl);
+    }
+    return ozoneAclList;
+  }
+
+  private List<OzoneAcl> getAndConvertAclOnVolume(String value,
+      String permission) throws OS3Exception {
+    List<OzoneAcl> ozoneAclList = new ArrayList<>();
+    if (StringUtils.isEmpty(value)) {
+      return ozoneAclList;
+    }
+    String[] subValues = value.split(",");
+    for (String acl: subValues) {
+      String[] part = acl.split("=");
+      if (part.length != 2) {
+        throw S3ErrorTable.newError(S3ErrorTable.INVALID_ARGUMENT, acl);
+      }
+      S3Acl.ACLIdentityType type =
+          S3Acl.ACLIdentityType.getTypeFromHeaderType(part[0]);
+      if (type == null || !type.isSupported()) {
+        LOG.warn("S3 grantee {} is null or not supported", part[0]);
+        throw S3ErrorTable.newError(NOT_IMPLEMENTED, part[0]);
+      }
+      // Build ACL on Volume
+      BitSet aclsOnVolume =
+          S3Acl.getOzoneAclOnVolumeFromS3Permission(permission);
+      OzoneAcl defaultOzoneAcl = new OzoneAcl(
+          IAccessAuthorizer.ACLIdentityType.USER, part[1], aclsOnVolume,

Review comment:
       I don't this we should populate DEFAULT ACL on Volume with the same permission. This will affect all new buckets create after that. 
   
   For example if user **foo** change its bucket acl to allow full control of user **bar** on bucket1, but as a result of that, the default acl for user **bar** with full control was added on volume. user **bar**  will will gain full control on all volume/buckets created subsequently. 
   
   




-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



---------------------------------------------------------------------
To unsubscribe, e-mail: issues-unsubscribe@ozone.apache.org
For additional commands, e-mail: issues-help@ozone.apache.org