use of org.apache.hadoop.fs.permission.AclEntryType in project hadoop by apache.
the class AclTransformation method buildAndValidateAcl.
/**
* Builds the final list of ACL entries to return by trimming, sorting and
* validating the ACL entries that have been added.
*
* @param aclBuilder ArrayList<AclEntry> containing entries to build
* @return List<AclEntry> unmodifiable, sorted list of ACL entries
* @throws AclException if validation fails
*/
private static List<AclEntry> buildAndValidateAcl(ArrayList<AclEntry> aclBuilder) throws AclException {
aclBuilder.trimToSize();
Collections.sort(aclBuilder, ACL_ENTRY_COMPARATOR);
// Full iteration to check for duplicates and invalid named entries.
AclEntry prevEntry = null;
for (AclEntry entry : aclBuilder) {
if (prevEntry != null && ACL_ENTRY_COMPARATOR.compare(prevEntry, entry) == 0) {
throw new AclException("Invalid ACL: multiple entries with same scope, type and name.");
}
if (entry.getName() != null && (entry.getType() == MASK || entry.getType() == OTHER)) {
throw new AclException("Invalid ACL: this entry type must not have a name: " + entry + ".");
}
prevEntry = entry;
}
ScopedAclEntries scopedEntries = new ScopedAclEntries(aclBuilder);
checkMaxEntries(scopedEntries);
// then do the same check on the default entries.
for (AclEntryType type : EnumSet.of(USER, GROUP, OTHER)) {
AclEntry accessEntryKey = new AclEntry.Builder().setScope(ACCESS).setType(type).build();
if (Collections.binarySearch(scopedEntries.getAccessEntries(), accessEntryKey, ACL_ENTRY_COMPARATOR) < 0) {
throw new AclException("Invalid ACL: the user, group and other entries are required.");
}
if (!scopedEntries.getDefaultEntries().isEmpty()) {
AclEntry defaultEntryKey = new AclEntry.Builder().setScope(DEFAULT).setType(type).build();
if (Collections.binarySearch(scopedEntries.getDefaultEntries(), defaultEntryKey, ACL_ENTRY_COMPARATOR) < 0) {
throw new AclException("Invalid default ACL: the user, group and other entries are required.");
}
}
}
return Collections.unmodifiableList(aclBuilder);
}
use of org.apache.hadoop.fs.permission.AclEntryType in project hadoop by apache.
the class AclStorage method copyINodeDefaultAcl.
/**
* If a default ACL is defined on a parent directory, then copies that default
* ACL to a newly created child file or directory.
*
* @param child INode newly created child
*/
public static boolean copyINodeDefaultAcl(INode child) {
INodeDirectory parent = child.getParent();
AclFeature parentAclFeature = parent.getAclFeature();
if (parentAclFeature == null || !(child.isFile() || child.isDirectory())) {
return false;
}
// Split parent's entries into access vs. default.
List<AclEntry> featureEntries = getEntriesFromAclFeature(parent.getAclFeature());
ScopedAclEntries scopedEntries = new ScopedAclEntries(featureEntries);
List<AclEntry> parentDefaultEntries = scopedEntries.getDefaultEntries();
// The parent may have an access ACL but no default ACL. If so, exit.
if (parentDefaultEntries.isEmpty()) {
return false;
}
// Pre-allocate list size for access entries to copy from parent.
List<AclEntry> accessEntries = Lists.newArrayListWithCapacity(parentDefaultEntries.size());
FsPermission childPerm = child.getFsPermission();
// Copy each default ACL entry from parent to new child's access ACL.
boolean parentDefaultIsMinimal = AclUtil.isMinimalAcl(parentDefaultEntries);
for (AclEntry entry : parentDefaultEntries) {
AclEntryType type = entry.getType();
String name = entry.getName();
AclEntry.Builder builder = new AclEntry.Builder().setScope(AclEntryScope.ACCESS).setType(type).setName(name);
// The child's initial permission bits are treated as the mode parameter,
// which can filter copied permission values for owner, mask and other.
final FsAction permission;
if (type == AclEntryType.USER && name == null) {
permission = entry.getPermission().and(childPerm.getUserAction());
} else if (type == AclEntryType.GROUP && parentDefaultIsMinimal) {
// This only happens if the default ACL is a minimal ACL: exactly 3
// entries corresponding to owner, group and other. In this case,
// filter the group permissions.
permission = entry.getPermission().and(childPerm.getGroupAction());
} else if (type == AclEntryType.MASK) {
// Group bits from mode parameter filter permission of mask entry.
permission = entry.getPermission().and(childPerm.getGroupAction());
} else if (type == AclEntryType.OTHER) {
permission = entry.getPermission().and(childPerm.getOtherAction());
} else {
permission = entry.getPermission();
}
builder.setPermission(permission);
accessEntries.add(builder.build());
}
// A new directory also receives a copy of the parent's default ACL.
List<AclEntry> defaultEntries = child.isDirectory() ? parentDefaultEntries : Collections.<AclEntry>emptyList();
final FsPermission newPerm;
if (!AclUtil.isMinimalAcl(accessEntries) || !defaultEntries.isEmpty()) {
// Save the new ACL to the child.
child.addAclFeature(createAclFeature(accessEntries, defaultEntries));
newPerm = createFsPermissionForExtendedAcl(accessEntries, childPerm);
} else {
// The child is receiving a minimal ACL.
newPerm = createFsPermissionForMinimalAcl(accessEntries, childPerm);
}
child.setPermission(newPerm);
return true;
}
use of org.apache.hadoop.fs.permission.AclEntryType in project hadoop by apache.
the class AclTransformation method copyDefaultsIfNeeded.
/**
* Adds unspecified default entries by copying permissions from the
* corresponding access entries.
*
* @param aclBuilder ArrayList<AclEntry> containing entries to build
*/
private static void copyDefaultsIfNeeded(List<AclEntry> aclBuilder) {
Collections.sort(aclBuilder, ACL_ENTRY_COMPARATOR);
ScopedAclEntries scopedEntries = new ScopedAclEntries(aclBuilder);
if (!scopedEntries.getDefaultEntries().isEmpty()) {
List<AclEntry> accessEntries = scopedEntries.getAccessEntries();
List<AclEntry> defaultEntries = scopedEntries.getDefaultEntries();
List<AclEntry> copiedEntries = Lists.newArrayListWithCapacity(3);
for (AclEntryType type : EnumSet.of(USER, GROUP, OTHER)) {
AclEntry defaultEntryKey = new AclEntry.Builder().setScope(DEFAULT).setType(type).build();
int defaultEntryIndex = Collections.binarySearch(defaultEntries, defaultEntryKey, ACL_ENTRY_COMPARATOR);
if (defaultEntryIndex < 0) {
AclEntry accessEntryKey = new AclEntry.Builder().setScope(ACCESS).setType(type).build();
int accessEntryIndex = Collections.binarySearch(accessEntries, accessEntryKey, ACL_ENTRY_COMPARATOR);
if (accessEntryIndex >= 0) {
copiedEntries.add(new AclEntry.Builder().setScope(DEFAULT).setType(type).setPermission(accessEntries.get(accessEntryIndex).getPermission()).build());
}
}
}
// Add all copied entries when done to prevent potential issues with binary
// search on a modified aclBulider during the main loop.
aclBuilder.addAll(copiedEntries);
}
}
use of org.apache.hadoop.fs.permission.AclEntryType in project hadoop by apache.
the class FSPermissionChecker method hasAclPermission.
/**
* Checks requested access against an Access Control List. This method relies
* on finding the ACL data in the relevant portions of {@link FsPermission} and
* {@link AclFeature} as implemented in the logic of {@link AclStorage}. This
* method also relies on receiving the ACL entries in sorted order. This is
* assumed to be true, because the ACL modification methods in
* {@link AclTransformation} sort the resulting entries.
*
* More specifically, this method depends on these invariants in an ACL:
* - The list must be sorted.
* - Each entry in the list must be unique by scope + type + name.
* - There is exactly one each of the unnamed user/group/other entries.
* - The mask entry must not have a name.
* - The other entry must not have a name.
* - Default entries may be present, but they are ignored during enforcement.
*
* @param inode INodeAttributes accessed inode
* @param snapshotId int snapshot ID
* @param access FsAction requested permission
* @param mode FsPermission mode from inode
* @param aclFeature AclFeature of inode
* @throws AccessControlException if the ACL denies permission
*/
private boolean hasAclPermission(INodeAttributes inode, FsAction access, FsPermission mode, AclFeature aclFeature) {
boolean foundMatch = false;
// Use owner entry from permission bits if user is owner.
if (getUser().equals(inode.getUserName())) {
if (mode.getUserAction().implies(access)) {
return true;
}
foundMatch = true;
}
// Check named user and group entries if user was not denied by owner entry.
if (!foundMatch) {
for (int pos = 0, entry; pos < aclFeature.getEntriesSize(); pos++) {
entry = aclFeature.getEntryAt(pos);
if (AclEntryStatusFormat.getScope(entry) == AclEntryScope.DEFAULT) {
break;
}
AclEntryType type = AclEntryStatusFormat.getType(entry);
String name = AclEntryStatusFormat.getName(entry);
if (type == AclEntryType.USER) {
// matches name.
if (getUser().equals(name)) {
FsAction masked = AclEntryStatusFormat.getPermission(entry).and(mode.getGroupAction());
if (masked.implies(access)) {
return true;
}
foundMatch = true;
break;
}
} else if (type == AclEntryType.GROUP) {
// Use group entry (unnamed or named) with mask from permission bits
// applied if user is a member and entry grants access. If user is a
// member of multiple groups that have entries that grant access, then
// it doesn't matter which is chosen, so exit early after first match.
String group = name == null ? inode.getGroupName() : name;
if (isMemberOfGroup(group)) {
FsAction masked = AclEntryStatusFormat.getPermission(entry).and(mode.getGroupAction());
if (masked.implies(access)) {
return true;
}
foundMatch = true;
}
}
}
}
// Use other entry if user was not denied by an earlier match.
return !foundMatch && mode.getOtherAction().implies(access);
}
Aggregations