You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ozone.apache.org by xy...@apache.org on 2021/06/11 18:41:53 UTC
[ozone] branch master updated: HDDS-4913. Refine the native
authorizer parent context right check. (#2012)
This is an automated email from the ASF dual-hosted git repository.
xyao pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ozone.git
The following commit(s) were added to refs/heads/master by this push:
new 2262395 HDDS-4913. Refine the native authorizer parent context right check. (#2012)
2262395 is described below
commit 2262395ca5b523735fb2535700d31e07f2dc9cbf
Author: Xiaoyu Yao <xy...@apache.org>
AuthorDate: Fri Jun 11 11:41:35 2021 -0700
HDDS-4913. Refine the native authorizer parent context right check. (#2012)
---
.../ozone/security/acl/OzoneNativeAuthorizer.java | 35 +-
.../hadoop/ozone/security/acl/TestParentAcl.java | 411 +++++++++++++++++++++
2 files changed, 434 insertions(+), 12 deletions(-)
diff --git a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/security/acl/OzoneNativeAuthorizer.java b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/security/acl/OzoneNativeAuthorizer.java
index 2521b76..b33a6af 100644
--- a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/security/acl/OzoneNativeAuthorizer.java
+++ b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/security/acl/OzoneNativeAuthorizer.java
@@ -80,7 +80,6 @@ public class OzoneNativeAuthorizer implements IAccessAuthorizer {
OzoneObjInfo objInfo;
RequestContext parentContext;
boolean isACLTypeCreate = (context.getAclRights() == ACLType.CREATE);
- boolean isACLTypeDelete = (context.getAclRights() == ACLType.DELETE);
if (ozObject instanceof OzoneObjInfo) {
objInfo = (OzoneObjInfo) ozObject;
@@ -102,20 +101,32 @@ public class OzoneNativeAuthorizer implements IAccessAuthorizer {
return getAllowListAllVolumes();
}
- // For CREATE and DELETE acl requests, the parents need to be checked
- // for WRITE acl. If Key create request is received, then we need to
- // check if user has WRITE acl set on Bucket and Volume. In all other cases
- // the parents also need to be checked for the same acl type.
- if (isACLTypeCreate || isACLTypeDelete) {
- parentContext = RequestContext.newBuilder()
+ // Refined the parent context
+ // OP |CHILD |PARENT
+
+ // CREATE NONE WRITE
+ // DELETE DELETE WRITE
+ // WRITE WRITE WRITE
+ // WRITE_ACL WRITE_ACL WRITE (V1 WRITE_ACL=>WRITE)
+
+ // READ READ READ
+ // LIST LIST READ (V1 LIST=>READ)
+ // READ_ACL READ_ACL READ (V1 READ_ACL=>READ)
+
+ ACLType aclRight = context.getAclRights();
+ ACLType parentAclRight = aclRight;
+
+ if (aclRight == ACLType.CREATE || aclRight == ACLType.DELETE ||
+ aclRight == ACLType.WRITE_ACL) {
+ parentAclRight = ACLType.WRITE;
+ } else if (aclRight == ACLType.READ_ACL || aclRight == ACLType.LIST) {
+ parentAclRight = ACLType.READ;
+ }
+ parentContext = RequestContext.newBuilder()
.setClientUgi(context.getClientUgi())
.setIp(context.getIp())
.setAclType(context.getAclType())
- .setAclRights(ACLType.WRITE)
- .build();
- } else {
- parentContext = context;
- }
+ .setAclRights(parentAclRight).build();
switch (objInfo.getResourceType()) {
case VOLUME:
diff --git a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/security/acl/TestParentAcl.java b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/security/acl/TestParentAcl.java
new file mode 100644
index 0000000..d0b4efe
--- /dev/null
+++ b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/security/acl/TestParentAcl.java
@@ -0,0 +1,411 @@
+/**
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.apache.hadoop.ozone.security.acl;
+
+import com.google.common.base.Optional;
+import org.apache.commons.lang3.RandomUtils;
+import org.apache.hadoop.hdds.client.StandaloneReplicationConfig;
+import org.apache.hadoop.hdds.conf.OzoneConfiguration;
+import org.apache.hadoop.hdds.protocol.proto.HddsProtos;
+import org.apache.hadoop.hdds.scm.protocol.ScmBlockLocationProtocol;
+import org.apache.hadoop.hdds.utils.db.cache.CacheKey;
+import org.apache.hadoop.hdds.utils.db.cache.CacheValue;
+import org.apache.hadoop.ozone.OzoneAcl;
+import org.apache.hadoop.ozone.om.BucketManagerImpl;
+import org.apache.hadoop.ozone.om.KeyManagerImpl;
+import org.apache.hadoop.ozone.om.OMMetadataManager;
+import org.apache.hadoop.ozone.om.OmMetadataManagerImpl;
+import org.apache.hadoop.ozone.om.PrefixManager;
+import org.apache.hadoop.ozone.om.PrefixManagerImpl;
+import org.apache.hadoop.ozone.om.VolumeManagerImpl;
+import org.apache.hadoop.ozone.om.helpers.OmBucketInfo;
+import org.apache.hadoop.ozone.om.helpers.OmKeyArgs;
+import org.apache.hadoop.ozone.om.helpers.OmKeyInfo;
+import org.apache.hadoop.ozone.om.helpers.OmVolumeArgs;
+import org.apache.hadoop.ozone.om.helpers.OpenKeySession;
+import org.apache.hadoop.ozone.om.helpers.OzoneAclUtil;
+import org.apache.hadoop.ozone.om.request.TestOMRequestUtils;
+import org.apache.hadoop.ozone.security.acl.IAccessAuthorizer.ACLType;
+import org.apache.hadoop.security.UserGroupInformation;
+import org.apache.ozone.test.GenericTestUtils;
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Collections;
+import java.util.List;
+
+import static org.apache.hadoop.hdds.HddsConfigKeys.OZONE_METADATA_DIRS;
+import static org.apache.hadoop.ozone.OzoneAcl.AclScope.ACCESS;
+import static org.apache.hadoop.ozone.OzoneConfigKeys.OZONE_ACL_AUTHORIZER_CLASS;
+import static org.apache.hadoop.ozone.OzoneConfigKeys.OZONE_ACL_AUTHORIZER_CLASS_NATIVE;
+import static org.apache.hadoop.ozone.OzoneConfigKeys.OZONE_ADMINISTRATORS;
+import static org.apache.hadoop.ozone.OzoneConsts.OZONE_URI_DELIMITER;
+import static org.apache.hadoop.ozone.security.acl.IAccessAuthorizer.ACLIdentityType.USER;
+import static org.apache.hadoop.ozone.security.acl.IAccessAuthorizer.ACLType.ALL;
+import static org.apache.hadoop.ozone.security.acl.IAccessAuthorizer.ACLType.CREATE;
+import static org.apache.hadoop.ozone.security.acl.IAccessAuthorizer.ACLType.DELETE;
+import static org.apache.hadoop.ozone.security.acl.IAccessAuthorizer.ACLType.LIST;
+import static org.apache.hadoop.ozone.security.acl.IAccessAuthorizer.ACLType.READ;
+import static org.apache.hadoop.ozone.security.acl.IAccessAuthorizer.ACLType.READ_ACL;
+import static org.apache.hadoop.ozone.security.acl.IAccessAuthorizer.ACLType.WRITE;
+import static org.apache.hadoop.ozone.security.acl.IAccessAuthorizer.ACLType.WRITE_ACL;
+import static org.apache.hadoop.ozone.security.acl.OzoneObj.ResourceType.BUCKET;
+import static org.apache.hadoop.ozone.security.acl.OzoneObj.ResourceType.KEY;
+import static org.apache.hadoop.ozone.security.acl.OzoneObj.ResourceType.VOLUME;
+import static org.apache.hadoop.ozone.security.acl.OzoneObj.StoreType.OZONE;
+import static org.mockito.Mockito.mock;
+
+/**
+ * Test parent acl requirements when accessing children with native authorizer.
+ */
+public class TestParentAcl {
+ private static OzoneConfiguration ozConfig;
+ private static KeyManagerImpl keyManager;
+ private static VolumeManagerImpl volumeManager;
+ private static BucketManagerImpl bucketManager;
+ private static PrefixManager prefixManager;
+ private static OMMetadataManager metadataManager;
+ private static OzoneNativeAuthorizer nativeAuthorizer;
+ private static UserGroupInformation adminUgi;
+ private static UserGroupInformation testUgi, testUgi1;
+
+ @BeforeClass
+ public static void setup() throws IOException {
+ ozConfig = new OzoneConfiguration();
+ ozConfig.set(OZONE_ACL_AUTHORIZER_CLASS,
+ OZONE_ACL_AUTHORIZER_CLASS_NATIVE);
+ File dir = GenericTestUtils.getRandomizedTestDir();
+ ozConfig.set(OZONE_METADATA_DIRS, dir.toString());
+ ozConfig.set(OZONE_ADMINISTRATORS, "om");
+
+ metadataManager = new OmMetadataManagerImpl(ozConfig);
+ volumeManager = new VolumeManagerImpl(metadataManager, ozConfig);
+ bucketManager = new BucketManagerImpl(metadataManager);
+ prefixManager = new PrefixManagerImpl(metadataManager, false);
+
+ keyManager = new KeyManagerImpl(mock(ScmBlockLocationProtocol.class),
+ metadataManager, ozConfig, "om1", null);
+
+ nativeAuthorizer = new OzoneNativeAuthorizer(volumeManager, bucketManager,
+ keyManager, prefixManager,
+ Collections.singletonList("om"));
+ adminUgi = UserGroupInformation.createUserForTesting("om",
+ new String[]{"ozone"});
+ testUgi = UserGroupInformation.createUserForTesting("testuser",
+ new String[]{"test"});
+ testUgi1 = UserGroupInformation.createUserForTesting("testuser1",
+ new String[]{"test1"});
+ }
+
+ // Refined the parent context
+ // OP |CHILD |PARENT
+
+ // CREATE NONE WRITE
+ // DELETE DELETE WRITE
+ // WRITE WRITE WRITE
+ // WRITE_ACL WRITE_ACL WRITE (V1 WRITE_ACL=>WRITE)
+
+ // READ READ READ
+ // LIST LIST READ (V1 LIST=>READ)
+ // READ_ACL READ_ACL READ (V1 READ_ACL=>READ)
+ @Test
+ public void testKeyAcl()
+ throws IOException {
+ OzoneObj keyObj;
+ int randomInt = RandomUtils.nextInt();
+ String vol = "vol" + randomInt;
+ String buck = "bucket" + randomInt;
+ String key = "key" + randomInt;
+
+ createVolume(vol);
+ createBucket(vol, buck);
+ keyObj = createKey(vol, buck, key);
+
+ List<OzoneAcl> originalVolAcls = getVolumeAcls(vol);
+ List<OzoneAcl> originalBuckAcls = getBucketAcls(vol, buck);
+ List<OzoneAcl> originalKeyAcls = getBucketAcls(vol, buck);
+
+ testParentChild(keyObj, WRITE, WRITE_ACL);
+ resetAcl(vol, originalVolAcls, buck, originalBuckAcls,
+ key, originalKeyAcls);
+
+ testParentChild(keyObj, WRITE, DELETE);
+ resetAcl(vol, originalVolAcls, buck, originalBuckAcls,
+ key, originalKeyAcls);
+
+ testParentChild(keyObj, READ, READ_ACL);
+ resetAcl(vol, originalVolAcls, buck, originalBuckAcls,
+ key, originalKeyAcls);
+
+ testParentChild(keyObj, READ, LIST);
+ resetAcl(vol, originalVolAcls, buck, originalBuckAcls,
+ key, originalKeyAcls);
+
+ testParentChild(keyObj, WRITE, CREATE);
+ resetAcl(vol, originalVolAcls, buck, originalBuckAcls,
+ key, originalKeyAcls);
+
+ testParentChild(keyObj, WRITE, WRITE);
+ resetAcl(vol, originalVolAcls, buck, originalBuckAcls,
+ key, originalKeyAcls);
+
+ testParentChild(keyObj, READ, READ);
+ resetAcl(vol, originalVolAcls, buck, originalBuckAcls,
+ key, originalKeyAcls);
+ }
+
+ @Test
+ public void testBucketAcl()
+ throws IOException {
+ OzoneObj bucketObj;
+ int randomInt = RandomUtils.nextInt();
+ String vol = "vol" + randomInt;
+ String buck = "bucket" + randomInt;
+
+ createVolume(vol);
+ bucketObj = createBucket(vol, buck);
+
+ List<OzoneAcl> originalVolAcls = getVolumeAcls(vol);
+ List<OzoneAcl> originalBuckAcls = getBucketAcls(vol, buck);
+ testParentChild(bucketObj, WRITE, WRITE_ACL);
+ resetAcl(vol, originalVolAcls, buck, originalBuckAcls, null, null);
+
+ testParentChild(bucketObj, WRITE, DELETE);
+ resetAcl(vol, originalVolAcls, buck, originalBuckAcls, null, null);
+
+ testParentChild(bucketObj, READ, READ_ACL);
+ resetAcl(vol, originalVolAcls, buck, originalBuckAcls, null, null);
+
+ testParentChild(bucketObj, READ, LIST);
+ resetAcl(vol, originalVolAcls, buck, originalBuckAcls, null, null);
+
+ testParentChild(bucketObj, WRITE, CREATE);
+ resetAcl(vol, originalVolAcls, buck, originalBuckAcls, null, null);
+
+ testParentChild(bucketObj, READ, READ);
+ resetAcl(vol, originalVolAcls, buck, originalBuckAcls, null, null);
+
+ testParentChild(bucketObj, WRITE, WRITE);
+ resetAcl(vol, originalVolAcls, buck, originalBuckAcls, null, null);
+ }
+
+ private void resetAcl(String vol, List<OzoneAcl> volAcls,
+ String buck, List<OzoneAcl> buckAcls,
+ String key, List<OzoneAcl> keyAcls) throws IOException {
+ if (volAcls != null) {
+ setVolumeAcl(vol, volAcls);
+ }
+
+ if (buckAcls != null) {
+ setBucketAcl(vol, buck, buckAcls);
+ }
+
+ if (keyAcls != null) {
+ setKeyAcl(vol, buck, key, keyAcls);
+ }
+ }
+
+ private void testParentChild(OzoneObj child,
+ ACLType parentAclType, ACLType childAclType) throws IOException {
+
+ RequestContext requestContext = new RequestContext.Builder()
+ .setClientUgi(testUgi1)
+ .setAclType(USER)
+ .setAclRights(childAclType).build();
+
+ OzoneAcl childAcl = new OzoneAcl(USER,
+ testUgi1.getUserName(), childAclType, ACCESS);
+
+ OzoneAcl parentAcl = new OzoneAcl(USER,
+ testUgi1.getUserName(), parentAclType, ACCESS);
+
+ Assert.assertFalse(nativeAuthorizer.checkAccess(child, requestContext));
+ if (child.getResourceType() == BUCKET) {
+ // add the bucket acl
+ addBucketAcl(child.getVolumeName(), child.getBucketName(), childAcl);
+ Assert.assertFalse(nativeAuthorizer.checkAccess(child, requestContext));
+
+ // add the volume acl (parent), now bucket access is allowed.
+ addVolumeAcl(child.getVolumeName(), parentAcl);
+ Assert.assertTrue(nativeAuthorizer.checkAccess(child, requestContext));
+
+ } else if (child.getResourceType() == KEY) {
+ // add key acl is not enough
+ addKeyAcl(child.getVolumeName(), child.getBucketName(),
+ child.getKeyName(), childAcl);
+ Assert.assertFalse(nativeAuthorizer.checkAccess(child, requestContext));
+
+ // add the bucket acl is not enough (parent)
+ addBucketAcl(child.getVolumeName(), child.getBucketName(), parentAcl);
+ Assert.assertFalse(nativeAuthorizer.checkAccess(child, requestContext));
+
+ // add the volume acl (grand-parent), now key access is allowed.
+ addVolumeAcl(child.getVolumeName(), parentAcl);
+ Assert.assertTrue(nativeAuthorizer.checkAccess(child, requestContext));
+ }
+ }
+
+ private void addVolumeAcl(String vol, OzoneAcl ozoneAcl) throws IOException {
+ String volumeKey = metadataManager.getVolumeKey(vol);
+ OmVolumeArgs omVolumeArgs =
+ metadataManager.getVolumeTable().get(volumeKey);
+
+ omVolumeArgs.addAcl(ozoneAcl);
+
+ metadataManager.getVolumeTable().addCacheEntry(new CacheKey<>(volumeKey),
+ new CacheValue<>(Optional.of(omVolumeArgs), 1L));
+ }
+
+ private List<OzoneAcl> getVolumeAcls(String vol) throws IOException {
+ String volumeKey = metadataManager.getVolumeKey(vol);
+ OmVolumeArgs omVolumeArgs =
+ metadataManager.getVolumeTable().get(volumeKey);
+
+ return omVolumeArgs.getAcls();
+ }
+
+ private void setVolumeAcl(String vol, List<OzoneAcl> ozoneAcls)
+ throws IOException {
+ String volumeKey = metadataManager.getVolumeKey(vol);
+ OmVolumeArgs omVolumeArgs = metadataManager.getVolumeTable().get(volumeKey);
+
+ omVolumeArgs.setAcls(ozoneAcls);
+
+ metadataManager.getVolumeTable().addCacheEntry(new CacheKey<>(volumeKey),
+ new CacheValue<>(Optional.of(omVolumeArgs), 1L));
+ }
+
+ private void addKeyAcl(String vol, String buck, String key,
+ OzoneAcl ozoneAcl) throws IOException {
+ String objKey = metadataManager.getOzoneKey(vol, buck, key);
+ OmKeyInfo omKeyInfo = metadataManager.getKeyTable().get(objKey);
+
+ omKeyInfo.addAcl(ozoneAcl);
+
+ metadataManager.getKeyTable().addCacheEntry(new CacheKey<>(objKey),
+ new CacheValue<>(Optional.of(omKeyInfo), 1L));
+ }
+
+ private void setKeyAcl(String vol, String buck, String key,
+ List<OzoneAcl> ozoneAcls) throws IOException {
+ String objKey = metadataManager.getOzoneKey(vol, buck, key);
+ OmKeyInfo omKeyInfo = metadataManager.getKeyTable().get(objKey);
+ omKeyInfo.setAcls(ozoneAcls);
+
+ metadataManager.getKeyTable().addCacheEntry(new CacheKey<>(objKey),
+ new CacheValue<>(Optional.of(omKeyInfo), 1L));
+ }
+
+ private void addBucketAcl(String vol, String buck, OzoneAcl ozoneAcl)
+ throws IOException {
+ String bucketKey = metadataManager.getBucketKey(vol, buck);
+ OmBucketInfo omBucketInfo = metadataManager.getBucketTable().get(bucketKey);
+
+ omBucketInfo.addAcl(ozoneAcl);
+
+ metadataManager.getBucketTable().addCacheEntry(new CacheKey<>(bucketKey),
+ new CacheValue<>(Optional.of(omBucketInfo), 1L));
+ }
+
+ private List<OzoneAcl> getBucketAcls(String vol, String buck)
+ throws IOException {
+ String bucketKey = metadataManager.getBucketKey(vol, buck);
+ OmBucketInfo omBucketInfo = metadataManager.getBucketTable().get(bucketKey);
+
+ return omBucketInfo.getAcls();
+ }
+
+ private void setBucketAcl(String vol, String buck,
+ List<OzoneAcl> ozoneAcls) throws IOException {
+ String bucketKey = metadataManager.getBucketKey(vol, buck);
+ OmBucketInfo omBucketInfo = metadataManager.getBucketTable().get(bucketKey);
+
+ omBucketInfo.setAcls(ozoneAcls);
+
+ metadataManager.getBucketTable().addCacheEntry(new CacheKey<>(bucketKey),
+ new CacheValue<>(Optional.of(omBucketInfo), 1L));
+ }
+
+ private static OzoneObjInfo createVolume(String volumeName)
+ throws IOException {
+ OmVolumeArgs volumeArgs = OmVolumeArgs.newBuilder()
+ .setVolume(volumeName)
+ .setAdminName(adminUgi.getUserName())
+ .setOwnerName(testUgi.getUserName())
+ .build();
+ TestOMRequestUtils.addVolumeToOM(metadataManager, volumeArgs);
+ return new OzoneObjInfo.Builder()
+ .setVolumeName(volumeName)
+ .setResType(VOLUME)
+ .setStoreType(OZONE)
+ .build();
+ }
+
+ private static OzoneObjInfo createBucket(String volumeName, String bucketName)
+ throws IOException {
+ OmBucketInfo bucketInfo = OmBucketInfo.newBuilder()
+ .setVolumeName(volumeName)
+ .setBucketName(bucketName)
+ .build();
+ TestOMRequestUtils.addBucketToOM(metadataManager, bucketInfo);
+ return new OzoneObjInfo.Builder()
+ .setVolumeName(volumeName)
+ .setBucketName(bucketName)
+ .setResType(BUCKET)
+ .setStoreType(OZONE)
+ .build();
+ }
+
+ private OzoneObjInfo createKey(String volume, String bucket, String keyName)
+ throws IOException {
+ OmKeyArgs keyArgs = new OmKeyArgs.Builder()
+ .setVolumeName(volume)
+ .setBucketName(bucket)
+ .setKeyName(keyName)
+ .setReplicationConfig(new StandaloneReplicationConfig(
+ HddsProtos.ReplicationFactor.ONE))
+ .setDataSize(0)
+ // here we give test ugi full access
+ .setAcls(OzoneAclUtil.getAclList(testUgi.getUserName(),
+ testUgi.getGroupNames(), ALL, ALL))
+ .build();
+
+
+ if (keyName.split(OZONE_URI_DELIMITER).length > 1) {
+ keyManager.createDirectory(keyArgs);
+ } else {
+ OpenKeySession keySession = keyManager.createFile(keyArgs, true, false);
+ keyArgs.setLocationInfoList(
+ keySession.getKeyInfo().getLatestVersionLocations()
+ .getLocationList());
+ keyManager.commitKey(keyArgs, keySession.getId());
+ }
+
+ return new OzoneObjInfo.Builder()
+ .setVolumeName(volume)
+ .setBucketName(bucket)
+ .setKeyName(keyName)
+ .setResType(KEY)
+ .setStoreType(OZONE)
+ .build();
+ }
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@ozone.apache.org
For additional commands, e-mail: commits-help@ozone.apache.org