HDFS-7582. Enforce maximum number of ACL entries separately per access and default. (Contributed by Vinayakumar B)
(cherry picked from commit 29cf887b22
)
This commit is contained in:
parent
8ef3821356
commit
cd3692fe4b
|
@ -719,6 +719,9 @@ Release 2.8.0 - UNRELEASED
|
||||||
HDFS-8344. NameNode doesn't recover lease for files with missing blocks
|
HDFS-8344. NameNode doesn't recover lease for files with missing blocks
|
||||||
(raviprak)
|
(raviprak)
|
||||||
|
|
||||||
|
HDFS-7582. Enforce maximum number of ACL entries separately per access
|
||||||
|
and default. (vinayakumarb)
|
||||||
|
|
||||||
Release 2.7.2 - UNRELEASED
|
Release 2.7.2 - UNRELEASED
|
||||||
|
|
||||||
INCOMPATIBLE CHANGES
|
INCOMPATIBLE CHANGES
|
||||||
|
|
|
@ -271,10 +271,6 @@ final class AclTransformation {
|
||||||
*/
|
*/
|
||||||
private static List<AclEntry> buildAndValidateAcl(
|
private static List<AclEntry> buildAndValidateAcl(
|
||||||
ArrayList<AclEntry> aclBuilder) throws AclException {
|
ArrayList<AclEntry> aclBuilder) throws AclException {
|
||||||
if (aclBuilder.size() > MAX_ENTRIES) {
|
|
||||||
throw new AclException("Invalid ACL: ACL has " + aclBuilder.size() +
|
|
||||||
" entries, which exceeds maximum of " + MAX_ENTRIES + ".");
|
|
||||||
}
|
|
||||||
aclBuilder.trimToSize();
|
aclBuilder.trimToSize();
|
||||||
Collections.sort(aclBuilder, ACL_ENTRY_COMPARATOR);
|
Collections.sort(aclBuilder, ACL_ENTRY_COMPARATOR);
|
||||||
// Full iteration to check for duplicates and invalid named entries.
|
// Full iteration to check for duplicates and invalid named entries.
|
||||||
|
@ -292,9 +288,12 @@ final class AclTransformation {
|
||||||
}
|
}
|
||||||
prevEntry = entry;
|
prevEntry = entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ScopedAclEntries scopedEntries = new ScopedAclEntries(aclBuilder);
|
||||||
|
checkMaxEntries(scopedEntries);
|
||||||
|
|
||||||
// Search for the required base access entries. If there is a default ACL,
|
// Search for the required base access entries. If there is a default ACL,
|
||||||
// then do the same check on the default entries.
|
// then do the same check on the default entries.
|
||||||
ScopedAclEntries scopedEntries = new ScopedAclEntries(aclBuilder);
|
|
||||||
for (AclEntryType type: EnumSet.of(USER, GROUP, OTHER)) {
|
for (AclEntryType type: EnumSet.of(USER, GROUP, OTHER)) {
|
||||||
AclEntry accessEntryKey = new AclEntry.Builder().setScope(ACCESS)
|
AclEntry accessEntryKey = new AclEntry.Builder().setScope(ACCESS)
|
||||||
.setType(type).build();
|
.setType(type).build();
|
||||||
|
@ -316,6 +315,22 @@ final class AclTransformation {
|
||||||
return Collections.unmodifiableList(aclBuilder);
|
return Collections.unmodifiableList(aclBuilder);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check the max entries separately on access and default entries
|
||||||
|
// HDFS-7582
|
||||||
|
private static void checkMaxEntries(ScopedAclEntries scopedEntries)
|
||||||
|
throws AclException {
|
||||||
|
List<AclEntry> accessEntries = scopedEntries.getAccessEntries();
|
||||||
|
List<AclEntry> defaultEntries = scopedEntries.getDefaultEntries();
|
||||||
|
if (accessEntries.size() > MAX_ENTRIES) {
|
||||||
|
throw new AclException("Invalid ACL: ACL has " + accessEntries.size()
|
||||||
|
+ " access entries, which exceeds maximum of " + MAX_ENTRIES + ".");
|
||||||
|
}
|
||||||
|
if (defaultEntries.size() > MAX_ENTRIES) {
|
||||||
|
throw new AclException("Invalid ACL: ACL has " + defaultEntries.size()
|
||||||
|
+ " default entries, which exceeds maximum of " + MAX_ENTRIES + ".");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Calculates mask entries required for the ACL. Mask calculation is performed
|
* Calculates mask entries required for the ACL. Mask calculation is performed
|
||||||
* separately for each scope: access and default. This method is responsible
|
* separately for each scope: access and default. This method is responsible
|
||||||
|
@ -444,11 +459,8 @@ final class AclTransformation {
|
||||||
* @throws AclException if validation fails
|
* @throws AclException if validation fails
|
||||||
*/
|
*/
|
||||||
public ValidatedAclSpec(List<AclEntry> aclSpec) throws AclException {
|
public ValidatedAclSpec(List<AclEntry> aclSpec) throws AclException {
|
||||||
if (aclSpec.size() > MAX_ENTRIES) {
|
|
||||||
throw new AclException("Invalid ACL: ACL spec has " + aclSpec.size() +
|
|
||||||
" entries, which exceeds maximum of " + MAX_ENTRIES + ".");
|
|
||||||
}
|
|
||||||
Collections.sort(aclSpec, ACL_ENTRY_COMPARATOR);
|
Collections.sort(aclSpec, ACL_ENTRY_COMPARATOR);
|
||||||
|
checkMaxEntries(new ScopedAclEntries(aclSpec));
|
||||||
this.aclSpec = aclSpec;
|
this.aclSpec = aclSpec;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -31,11 +31,8 @@ import com.google.common.collect.Lists;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import org.apache.hadoop.fs.permission.AclEntry;
|
import org.apache.hadoop.fs.permission.AclEntry;
|
||||||
import org.apache.hadoop.fs.permission.AclEntryScope;
|
|
||||||
import org.apache.hadoop.fs.permission.AclEntryType;
|
|
||||||
import org.apache.hadoop.fs.permission.FsAction;
|
import org.apache.hadoop.fs.permission.FsAction;
|
||||||
import org.apache.hadoop.hdfs.protocol.AclException;
|
import org.apache.hadoop.hdfs.protocol.AclException;
|
||||||
import org.apache.hadoop.hdfs.server.namenode.AclTransformation;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests operations that modify ACLs. All tests in this suite have been
|
* Tests operations that modify ACLs. All tests in this suite have been
|
||||||
|
@ -45,10 +42,13 @@ import org.apache.hadoop.hdfs.server.namenode.AclTransformation;
|
||||||
public class TestAclTransformation {
|
public class TestAclTransformation {
|
||||||
|
|
||||||
private static final List<AclEntry> ACL_SPEC_TOO_LARGE;
|
private static final List<AclEntry> ACL_SPEC_TOO_LARGE;
|
||||||
|
private static final List<AclEntry> ACL_SPEC_DEFAULT_TOO_LARGE;
|
||||||
static {
|
static {
|
||||||
ACL_SPEC_TOO_LARGE = Lists.newArrayListWithCapacity(33);
|
ACL_SPEC_TOO_LARGE = Lists.newArrayListWithCapacity(33);
|
||||||
|
ACL_SPEC_DEFAULT_TOO_LARGE = Lists.newArrayListWithCapacity(33);
|
||||||
for (int i = 0; i < 33; ++i) {
|
for (int i = 0; i < 33; ++i) {
|
||||||
ACL_SPEC_TOO_LARGE.add(aclEntry(ACCESS, USER, "user" + i, ALL));
|
ACL_SPEC_TOO_LARGE.add(aclEntry(ACCESS, USER, "user" + i, ALL));
|
||||||
|
ACL_SPEC_DEFAULT_TOO_LARGE.add(aclEntry(DEFAULT, USER, "user" + i, ALL));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -351,6 +351,17 @@ public class TestAclTransformation {
|
||||||
filterAclEntriesByAclSpec(existing, ACL_SPEC_TOO_LARGE);
|
filterAclEntriesByAclSpec(existing, ACL_SPEC_TOO_LARGE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test(expected = AclException.class)
|
||||||
|
public void testFilterDefaultAclEntriesByAclSpecInputTooLarge()
|
||||||
|
throws AclException {
|
||||||
|
List<AclEntry> existing = new ImmutableList.Builder<AclEntry>()
|
||||||
|
.add(aclEntry(DEFAULT, USER, ALL))
|
||||||
|
.add(aclEntry(DEFAULT, GROUP, READ))
|
||||||
|
.add(aclEntry(DEFAULT, OTHER, NONE))
|
||||||
|
.build();
|
||||||
|
filterAclEntriesByAclSpec(existing, ACL_SPEC_DEFAULT_TOO_LARGE);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testFilterDefaultAclEntries() throws AclException {
|
public void testFilterDefaultAclEntries() throws AclException {
|
||||||
List<AclEntry> existing = new ImmutableList.Builder<AclEntry>()
|
List<AclEntry> existing = new ImmutableList.Builder<AclEntry>()
|
||||||
|
@ -719,6 +730,16 @@ public class TestAclTransformation {
|
||||||
mergeAclEntries(existing, ACL_SPEC_TOO_LARGE);
|
mergeAclEntries(existing, ACL_SPEC_TOO_LARGE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test(expected=AclException.class)
|
||||||
|
public void testMergeAclDefaultEntriesInputTooLarge() throws AclException {
|
||||||
|
List<AclEntry> existing = new ImmutableList.Builder<AclEntry>()
|
||||||
|
.add(aclEntry(DEFAULT, USER, ALL))
|
||||||
|
.add(aclEntry(DEFAULT, GROUP, READ))
|
||||||
|
.add(aclEntry(DEFAULT, OTHER, NONE))
|
||||||
|
.build();
|
||||||
|
mergeAclEntries(existing, ACL_SPEC_DEFAULT_TOO_LARGE);
|
||||||
|
}
|
||||||
|
|
||||||
@Test(expected=AclException.class)
|
@Test(expected=AclException.class)
|
||||||
public void testMergeAclEntriesResultTooLarge() throws AclException {
|
public void testMergeAclEntriesResultTooLarge() throws AclException {
|
||||||
ImmutableList.Builder<AclEntry> aclBuilder =
|
ImmutableList.Builder<AclEntry> aclBuilder =
|
||||||
|
@ -737,6 +758,24 @@ public class TestAclTransformation {
|
||||||
mergeAclEntries(existing, aclSpec);
|
mergeAclEntries(existing, aclSpec);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test(expected = AclException.class)
|
||||||
|
public void testMergeAclDefaultEntriesResultTooLarge() throws AclException {
|
||||||
|
ImmutableList.Builder<AclEntry> aclBuilder =
|
||||||
|
new ImmutableList.Builder<AclEntry>()
|
||||||
|
.add(aclEntry(DEFAULT, USER, ALL));
|
||||||
|
for (int i = 1; i <= 28; ++i) {
|
||||||
|
aclBuilder.add(aclEntry(DEFAULT, USER, "user" + i, READ));
|
||||||
|
}
|
||||||
|
aclBuilder
|
||||||
|
.add(aclEntry(DEFAULT, GROUP, READ))
|
||||||
|
.add(aclEntry(DEFAULT, MASK, READ))
|
||||||
|
.add(aclEntry(DEFAULT, OTHER, NONE));
|
||||||
|
List<AclEntry> existing = aclBuilder.build();
|
||||||
|
List<AclEntry> aclSpec = Lists.newArrayList(
|
||||||
|
aclEntry(DEFAULT, USER, "bruce", READ));
|
||||||
|
mergeAclEntries(existing, aclSpec);
|
||||||
|
}
|
||||||
|
|
||||||
@Test(expected=AclException.class)
|
@Test(expected=AclException.class)
|
||||||
public void testMergeAclEntriesDuplicateEntries() throws AclException {
|
public void testMergeAclEntriesDuplicateEntries() throws AclException {
|
||||||
List<AclEntry> existing = new ImmutableList.Builder<AclEntry>()
|
List<AclEntry> existing = new ImmutableList.Builder<AclEntry>()
|
||||||
|
@ -1091,6 +1130,16 @@ public class TestAclTransformation {
|
||||||
replaceAclEntries(existing, ACL_SPEC_TOO_LARGE);
|
replaceAclEntries(existing, ACL_SPEC_TOO_LARGE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test(expected=AclException.class)
|
||||||
|
public void testReplaceAclDefaultEntriesInputTooLarge() throws AclException {
|
||||||
|
List<AclEntry> existing = new ImmutableList.Builder<AclEntry>()
|
||||||
|
.add(aclEntry(DEFAULT, USER, ALL))
|
||||||
|
.add(aclEntry(DEFAULT, GROUP, READ))
|
||||||
|
.add(aclEntry(DEFAULT, OTHER, NONE))
|
||||||
|
.build();
|
||||||
|
replaceAclEntries(existing, ACL_SPEC_DEFAULT_TOO_LARGE);
|
||||||
|
}
|
||||||
|
|
||||||
@Test(expected=AclException.class)
|
@Test(expected=AclException.class)
|
||||||
public void testReplaceAclEntriesResultTooLarge() throws AclException {
|
public void testReplaceAclEntriesResultTooLarge() throws AclException {
|
||||||
List<AclEntry> existing = new ImmutableList.Builder<AclEntry>()
|
List<AclEntry> existing = new ImmutableList.Builder<AclEntry>()
|
||||||
|
|
Loading…
Reference in New Issue