Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,9 @@ public enum ResultCodes {

S3_BUCKET_INVALID_LENGTH,

RATIS_ERROR // Error in Ratis server
RATIS_ERROR, // Error in Ratis server

INVALID_PATH_IN_ACL_REQUEST // Error code when path name is invalid during
// acl requests.
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
package org.apache.hadoop.ozone.om.helpers;


import java.util.BitSet;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedList;
Expand All @@ -30,11 +31,14 @@
import org.apache.hadoop.ozone.OzoneAcl;
import org.apache.hadoop.ozone.OzoneConsts;
import org.apache.hadoop.ozone.audit.Auditable;
import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.BucketInfo;
import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos
.BucketInfo;
import org.apache.hadoop.ozone.protocolPB.OMPBHelper;

import com.google.common.base.Preconditions;

import static org.apache.hadoop.ozone.OzoneAcl.ZERO_BITSET;

/**
* A class that encapsulates Bucket Info.
*/
Expand Down Expand Up @@ -124,6 +128,95 @@ public List<OzoneAcl> getAcls() {
return acls;
}

/**
* Add an ozoneAcl to list of existing Acl set.
* @param ozoneAcl
* @return true - if successfully added, false if not added or acl is
* already existing in the acl list.
*/
public boolean addAcl(OzoneAcl ozoneAcl) {
// Case 1: When we are adding more rights to existing user/group.
boolean addToExistingAcl = false;
for(OzoneAcl existingAcl: getAcls()) {
if(existingAcl.getName().equals(ozoneAcl.getName()) &&
existingAcl.getType().equals(ozoneAcl.getType())) {

BitSet bits = (BitSet) ozoneAcl.getAclBitSet().clone();

// We need to do "or" before comparision because think of a case like
// existing acl is 777 and newly added acl is 444, we have already
// that acl set. In this case if we do direct check they will not
// be equal, but if we do or and then check, we shall know it
// has acl's already set or not.
bits.or(existingAcl.getAclBitSet());

if (bits.equals(existingAcl.getAclBitSet())) {
return false;
} else {
existingAcl.getAclBitSet().or(ozoneAcl.getAclBitSet());
addToExistingAcl = true;
break;
}
}
}

// Case 2: When a completely new acl is added.
if(!addToExistingAcl) {
getAcls().add(ozoneAcl);
}
return true;
}

/**
* Remove acl from existing acl list.
* @param ozoneAcl
* @return true - if successfully removed, false if not able to remove due
* to that acl is not in the existing acl list.
*/
public boolean removeAcl(OzoneAcl ozoneAcl) {
boolean removed = false;

// When we are removing subset of rights from existing acl.
for(OzoneAcl existingAcl: getAcls()) {
if (existingAcl.getName().equals(ozoneAcl.getName()) &&
existingAcl.getType().equals(ozoneAcl.getType())) {
BitSet bits = (BitSet) ozoneAcl.getAclBitSet().clone();
bits.and(existingAcl.getAclBitSet());

// This happens when the acl bitset is not existing for current name
// and type.
// Like a case we have 444 permission, 333 is asked to removed.
if (bits.equals(ZERO_BITSET)) {
return false;
}

// We have some matching. Remove them.
existingAcl.getAclBitSet().xor(bits);

// If existing acl has same bitset as passed acl bitset, remove that
// acl from the list
if (existingAcl.getAclBitSet().equals(ZERO_BITSET)) {
getAcls().remove(existingAcl);
}
removed = true;
break;
}
}

return removed;
}

/**
* Reset the existing acl list.
* @param ozoneAcls
* @return true - if successfully able to reset.
*/
public boolean setAcls(List<OzoneAcl> ozoneAcls) {
this.acls.clear();
this.acls = ozoneAcls;
return true;
}

/**
* Returns true if bucket version is enabled, else false.
* @return isVersionEnabled
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package org.apache.hadoop.ozone.util;

/**
* Defines a functional interface having two inputs and returns boolean as
* output.
*/
@FunctionalInterface
public interface BooleanBiFunction<LEFT, RIGHT> {
boolean apply(LEFT left, RIGHT right);
}

2 changes: 2 additions & 0 deletions hadoop-ozone/common/src/main/proto/OzoneManagerProtocol.proto
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,8 @@ enum Status {
S3_BUCKET_INVALID_LENGTH = 51; // s3 bucket invalid length.

RATIS_ERROR = 52;

INVALID_PATH_IN_ACL_REQUEST = 53; // Invalid path name in acl request.
}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,16 @@
import java.io.IOException;
import java.net.ConnectException;
import java.net.InetSocketAddress;
import java.util.BitSet;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

import org.apache.hadoop.ozone.OzoneAcl;
import org.apache.hadoop.ozone.security.acl.OzoneObj;
import org.apache.hadoop.ozone.security.acl.OzoneObjInfo;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
Expand Down Expand Up @@ -65,6 +70,7 @@

import static org.apache.hadoop.ozone.MiniOzoneHAClusterImpl
.NODE_FAILURE_TIMEOUT;
import static org.apache.hadoop.ozone.OzoneAcl.AclScope.DEFAULT;
import static org.apache.hadoop.ozone.OzoneConfigKeys.OZONE_ACL_ENABLED;
import static org.apache.hadoop.ozone.OzoneConfigKeys
.OZONE_CLIENT_FAILOVER_MAX_ATTEMPTS_KEY;
Expand All @@ -76,6 +82,9 @@
.OZONE_OPEN_KEY_EXPIRE_THRESHOLD_SECONDS;
import static org.apache.hadoop.ozone.om.exceptions.OMException.ResultCodes.FILE_ALREADY_EXISTS;
import static org.apache.hadoop.ozone.om.exceptions.OMException.ResultCodes.NOT_A_FILE;
import static org.apache.hadoop.ozone.security.acl.IAccessAuthorizer.ACLIdentityType.USER;
import static org.apache.hadoop.ozone.security.acl.IAccessAuthorizer.ACLType.READ;
import static org.apache.hadoop.ozone.security.acl.IAccessAuthorizer.ACLType.WRITE;
import static org.junit.Assert.fail;

/**
Expand Down Expand Up @@ -759,6 +768,139 @@ public void testReadRequest() throws Exception {
}
}

@Test
public void testAddBucketAcl() throws Exception {
OzoneBucket ozoneBucket = setupBucket();
String remoteUserName = "remoteUser";
OzoneAcl defaultUserAcl = new OzoneAcl(USER, remoteUserName,
READ, DEFAULT);

OzoneObj ozoneObj = OzoneObjInfo.Builder.newBuilder()
.setResType(OzoneObj.ResourceType.BUCKET)
.setStoreType(OzoneObj.StoreType.OZONE)
.setVolumeName(ozoneBucket.getVolumeName())
.setBucketName(ozoneBucket.getName()).build();

boolean addAcl = objectStore.addAcl(ozoneObj, defaultUserAcl);
Assert.assertTrue(addAcl);

List<OzoneAcl> acls = objectStore.getAcl(ozoneObj);

Assert.assertTrue(containsAcl(defaultUserAcl, acls));

// Add an already existing acl.
addAcl = objectStore.addAcl(ozoneObj, defaultUserAcl);
Assert.assertFalse(addAcl);

// Add an acl by changing acl type with same type, name and scope.
defaultUserAcl = new OzoneAcl(USER, remoteUserName,
WRITE, DEFAULT);
addAcl = objectStore.addAcl(ozoneObj, defaultUserAcl);
Assert.assertTrue(addAcl);
}

@Test
public void testRemoveBucketAcl() throws Exception {
OzoneBucket ozoneBucket = setupBucket();
String remoteUserName = "remoteUser";
OzoneAcl defaultUserAcl = new OzoneAcl(USER, remoteUserName,
READ, DEFAULT);

OzoneObj ozoneObj = OzoneObjInfo.Builder.newBuilder()
.setResType(OzoneObj.ResourceType.BUCKET)
.setStoreType(OzoneObj.StoreType.OZONE)
.setVolumeName(ozoneBucket.getVolumeName())
.setBucketName(ozoneBucket.getName()).build();

// As by default create bucket we add some default acls in RpcClient.
List<OzoneAcl> acls = objectStore.getAcl(ozoneObj);

Assert.assertTrue(acls.size() > 0);

// Remove an existing acl.
boolean removeAcl = objectStore.removeAcl(ozoneObj, acls.get(0));
Assert.assertTrue(removeAcl);

// Trying to remove an already removed acl.
removeAcl = objectStore.removeAcl(ozoneObj, acls.get(0));
Assert.assertFalse(removeAcl);

boolean addAcl = objectStore.addAcl(ozoneObj, defaultUserAcl);
Assert.assertTrue(addAcl);

// Just changed acl type here to write, rest all is same as defaultUserAcl.
OzoneAcl modifiedUserAcl = new OzoneAcl(USER, remoteUserName,
WRITE, DEFAULT);
addAcl = objectStore.addAcl(ozoneObj, modifiedUserAcl);
Assert.assertTrue(addAcl);

removeAcl = objectStore.removeAcl(ozoneObj, modifiedUserAcl);
Assert.assertTrue(removeAcl);

removeAcl = objectStore.removeAcl(ozoneObj, defaultUserAcl);
Assert.assertTrue(removeAcl);

}

@Test
public void testSetBucketAcl() throws Exception {
OzoneBucket ozoneBucket = setupBucket();
String remoteUserName = "remoteUser";
OzoneAcl defaultUserAcl = new OzoneAcl(USER, remoteUserName,
READ, DEFAULT);

OzoneObj ozoneObj = OzoneObjInfo.Builder.newBuilder()
.setResType(OzoneObj.ResourceType.BUCKET)
.setStoreType(OzoneObj.StoreType.OZONE)
.setVolumeName(ozoneBucket.getVolumeName())
.setBucketName(ozoneBucket.getName()).build();

// As by default create bucket we add some default acls in RpcClient.
List<OzoneAcl> acls = objectStore.getAcl(ozoneObj);

Assert.assertTrue(acls.size() > 0);

OzoneAcl modifiedUserAcl = new OzoneAcl(USER, remoteUserName,
WRITE, DEFAULT);

List<OzoneAcl> newAcls = Collections.singletonList(modifiedUserAcl);
boolean setAcl = objectStore.setAcl(ozoneObj, newAcls);
Assert.assertTrue(setAcl);

// Get acls and check whether they are reset or not.
List<OzoneAcl> getAcls = objectStore.getAcl(ozoneObj);

Assert.assertTrue(newAcls.size() == getAcls.size());
int i = 0;
for (OzoneAcl ozoneAcl : newAcls) {
Assert.assertTrue(compareAcls(getAcls.get(i++), ozoneAcl));
}
}

private boolean containsAcl(OzoneAcl ozoneAcl, List<OzoneAcl> ozoneAcls) {
for (OzoneAcl acl : ozoneAcls) {
boolean result = compareAcls(ozoneAcl, acl);
if (result) {
// We found a match, return.
return result;
}
}
return false;
}

private boolean compareAcls(OzoneAcl givenAcl, OzoneAcl existingAcl) {
if (givenAcl.getType().equals(existingAcl.getType())
&& givenAcl.getName().equals(existingAcl.getName())
&& givenAcl.getAclScope().equals(existingAcl.getAclScope())) {
BitSet bitSet = (BitSet) givenAcl.getAclBitSet().clone();
bitSet.and(existingAcl.getAclBitSet());
if (bitSet.equals(existingAcl.getAclBitSet())) {
return true;
}
}
return false;
}

@Test
public void testOMRatisSnapshot() throws Exception {
String userName = "user" + RandomStringUtils.randomNumeric(5);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@
import org.apache.hadoop.ozone.om.request.bucket.OMBucketDeleteRequest;
import org.apache.hadoop.ozone.om.request.bucket.OMBucketSetPropertyRequest;
import org.apache.hadoop.ozone.om.request.OMClientRequest;
import org.apache.hadoop.ozone.om.request.bucket.acl.OMBucketAddAclRequest;
import org.apache.hadoop.ozone.om.request.bucket.acl.OMBucketRemoveAclRequest;
import org.apache.hadoop.ozone.om.request.bucket.acl.OMBucketSetAclRequest;
import org.apache.hadoop.ozone.om.request.file.OMDirectoryCreateRequest;
import org.apache.hadoop.ozone.om.request.file.OMFileCreateRequest;
import org.apache.hadoop.ozone.om.request.key.OMAllocateBlockRequest;
Expand Down Expand Up @@ -136,19 +139,25 @@ private static OMClientRequest getOMAclRequest(OMRequest omRequest) {
ObjectType type = omRequest.getAddAclRequest().getObj().getResType();
if (ObjectType.VOLUME == type) {
return new OMVolumeAddAclRequest(omRequest);
} else if (ObjectType.BUCKET == type) {
return new OMBucketAddAclRequest(omRequest);
}
} else if (Type.RemoveAcl == cmdType) {
ObjectType type = omRequest.getAddAclRequest().getObj().getResType();
ObjectType type = omRequest.getRemoveAclRequest().getObj().getResType();
if (ObjectType.VOLUME == type) {
return new OMVolumeRemoveAclRequest(omRequest);
} else if (ObjectType.BUCKET == type) {
return new OMBucketRemoveAclRequest(omRequest);
}
} else if (Type.SetAcl == cmdType) {
ObjectType type = omRequest.getAddAclRequest().getObj().getResType();
ObjectType type = omRequest.getSetAclRequest().getObj().getResType();
if (ObjectType.VOLUME == type) {
return new OMVolumeSetAclRequest(omRequest);
} else if (ObjectType.BUCKET == type) {
return new OMBucketSetAclRequest(omRequest);
}
}
//TODO: handle bucket, key and prefix AddAcl
//TODO: handle key and prefix AddAcl
return null;
}

Expand Down
Loading