@Test public void testMultipleAclSpecParsing() throws Exception { List<AclEntry> parsedList = AclEntry.parseAclSpec( "group::rwx,user:user1:rwx,user:user2:rw-," + "group:group1:rw-,default:group:group1:rw-", true); AclEntry basicAcl = new AclEntry.Builder().setType(AclEntryType.GROUP) .setPermission(FsAction.ALL).build(); AclEntry user1Acl = new AclEntry.Builder().setType(AclEntryType.USER) .setPermission(FsAction.ALL).setName("user1").build(); AclEntry user2Acl = new AclEntry.Builder().setType(AclEntryType.USER) .setPermission(FsAction.READ_WRITE).setName("user2").build(); AclEntry group1Acl = new AclEntry.Builder().setType(AclEntryType.GROUP) .setPermission(FsAction.READ_WRITE).setName("group1").build(); AclEntry defaultAcl = new AclEntry.Builder().setType(AclEntryType.GROUP) .setPermission(FsAction.READ_WRITE).setName("group1") .setScope(AclEntryScope.DEFAULT).build(); List<AclEntry> expectedList = new ArrayList<AclEntry>(); expectedList.add(basicAcl); expectedList.add(user1Acl); expectedList.add(user2Acl); expectedList.add(group1Acl); expectedList.add(defaultAcl); assertEquals("Parsed Acl not correct", expectedList, parsedList); }
private static List<AclEntry> readAclEntriesFromXml(Stanza st) { List<AclEntry> aclEntries = Lists.newArrayList(); if (!st.hasChildren("ENTRY")) return null; List<Stanza> stanzas = st.getChildren("ENTRY"); for (Stanza s : stanzas) { AclEntry e = new AclEntry.Builder() .setScope(AclEntryScope.valueOf(s.getValue("SCOPE"))) .setType(AclEntryType.valueOf(s.getValue("TYPE"))) .setName(s.getValueOrNull("NAME")) .setPermission(fsActionFromXml(s)).build(); aclEntries.add(e); } return aclEntries; }
@Test public void testAclEntryProto() { // All fields populated. AclEntry e1 = new AclEntry.Builder().setName("test") .setPermission(FsAction.READ_EXECUTE).setScope(AclEntryScope.DEFAULT) .setType(AclEntryType.OTHER).build(); // No name. AclEntry e2 = new AclEntry.Builder().setScope(AclEntryScope.ACCESS) .setType(AclEntryType.USER).setPermission(FsAction.ALL).build(); // No permission, which will default to the 0'th enum element. AclEntry e3 = new AclEntry.Builder().setScope(AclEntryScope.ACCESS) .setType(AclEntryType.USER).setName("test").build(); AclEntry[] expected = new AclEntry[] { e1, e2, new AclEntry.Builder() .setScope(e3.getScope()) .setType(e3.getType()) .setName(e3.getName()) .setPermission(FsAction.NONE) .build() }; AclEntry[] actual = Lists.newArrayList( PBHelper.convertAclEntry(PBHelper.convertAclEntryProto(Lists .newArrayList(e1, e2, e3)))).toArray(new AclEntry[0]); Assert.assertArrayEquals(expected, actual); }
@Test public void testAclEntryProto() { // All fields populated. AclEntry e1 = new AclEntry.Builder().setName("test") .setPermission(FsAction.READ_EXECUTE).setScope(AclEntryScope.DEFAULT) .setType(AclEntryType.OTHER).build(); // No name. AclEntry e2 = new AclEntry.Builder().setScope(AclEntryScope.ACCESS) .setType(AclEntryType.USER).setPermission(FsAction.ALL).build(); // No permission, which will default to the 0'th enum element. AclEntry e3 = new AclEntry.Builder().setScope(AclEntryScope.ACCESS) .setType(AclEntryType.USER).setName("test").build(); AclEntry[] expected = new AclEntry[] { e1, e2, new AclEntry.Builder() .setScope(e3.getScope()) .setType(e3.getType()) .setName(e3.getName()) .setPermission(FsAction.NONE) .build() }; AclEntry[] actual = Lists.newArrayList( PBHelperClient.convertAclEntry(PBHelperClient.convertAclEntryProto(Lists .newArrayList(e1, e2, e3)))).toArray(new AclEntry[0]); Assert.assertArrayEquals(expected, actual); }
/** * Guarded by {@link FSNamesystem#readLock()} */ private void check(String user, Set<String> groups, INode inode, int snapshotId, FsAction access) throws AccessControlException { if (inode == null) { return; } FsPermission mode = inode.getFsPermission(snapshotId); AclFeature aclFeature = inode.getAclFeature(snapshotId); if (aclFeature != null) { List<AclEntry> featureEntries = aclFeature.getEntries(); // It's possible that the inode has a default ACL but no access ACL. if (featureEntries.get(0).getScope() == AclEntryScope.ACCESS) { checkAccessAcl(user, groups, inode, snapshotId, access, mode, featureEntries); return; } } checkFsPermission(user, groups, inode, snapshotId, access, mode); }
/** Guarded by {@link FSNamesystem#readLock()} */ private void check(INode inode, int snapshotId, FsAction access ) throws AccessControlException { if (inode == null) { return; } FsPermission mode = inode.getFsPermission(snapshotId); AclFeature aclFeature = inode.getAclFeature(snapshotId); if (aclFeature != null) { List<AclEntry> featureEntries = aclFeature.getEntries(); // It's possible that the inode has a default ACL but no access ACL. if (featureEntries.get(0).getScope() == AclEntryScope.ACCESS) { checkAccessAcl(inode, snapshotId, access, mode, featureEntries); return; } } checkFsPermission(inode, snapshotId, access, mode); }
/** * Translates the given permission bits to the equivalent minimal ACL. * * @param perm FsPermission to translate * @return List<AclEntry> containing exactly 3 entries representing the owner, * group and other permissions */ private static List<AclEntry> getMinimalAcl(FsPermission perm) { return Lists.newArrayList( new AclEntry.Builder() .setScope(AclEntryScope.ACCESS) .setType(AclEntryType.USER) .setPermission(perm.getUserAction()) .build(), new AclEntry.Builder() .setScope(AclEntryScope.ACCESS) .setType(AclEntryType.GROUP) .setPermission(perm.getGroupAction()) .build(), new AclEntry.Builder() .setScope(AclEntryScope.ACCESS) .setType(AclEntryType.OTHER) .setPermission(perm.getOtherAction()) .build()); }
private static List<AclEntry> readAclEntriesFromXml(Stanza st) { List<AclEntry> aclEntries = Lists.newArrayList(); if (!st.hasChildren("ENTRY")) return null; List<Stanza> stanzas = st.getChildren("ENTRY"); for (Stanza s : stanzas) { AclEntry e = new AclEntry.Builder() .setScope(AclEntryScope.valueOf(s.getValue("SCOPE"))) .setType(AclEntryType.valueOf(s.getValue("TYPE"))) .setName(s.getValue("NAME")) .setPermission(fsActionFromXml(s)).build(); aclEntries.add(e); } return aclEntries; }
/** * Prints a minimal ACL, consisting of exactly 3 ACL entries implied by the * permission bits. * * @param perm FsPermission of file */ private void printMinimalAcl(FsPermission perm) { out.println(new AclEntry.Builder() .setScope(AclEntryScope.ACCESS) .setType(AclEntryType.USER) .setPermission(perm.getUserAction()) .build()); out.println(new AclEntry.Builder() .setScope(AclEntryScope.ACCESS) .setType(AclEntryType.GROUP) .setPermission(perm.getGroupAction()) .build()); out.println(new AclEntry.Builder() .setScope(AclEntryScope.ACCESS) .setType(AclEntryType.OTHER) .setPermission(perm.getOtherAction()) .build()); }
private List<AclEntry> createAclEntries(String user, String group, FsPermission permission) { List<AclEntry> list = new ArrayList<AclEntry>(); AclEntry.Builder builder = new AclEntry.Builder(); FsPermission fsPerm = new FsPermission(permission); builder.setName(user); builder.setType(AclEntryType.USER); builder.setScope(AclEntryScope.ACCESS); builder.setPermission(fsPerm.getUserAction()); list.add(builder.build()); builder.setName(group); builder.setType(AclEntryType.GROUP); builder.setScope(AclEntryScope.ACCESS); builder.setPermission(fsPerm.getGroupAction()); list.add(builder.build()); builder.setName(null); return list; }
@Override public List<AclEntry> getAcls(String authzObj) { Map<String, FsAction> groupPerms = getGroupPerms(authzObj); List<AclEntry> retList = new LinkedList<AclEntry>(); for (Map.Entry<String, FsAction> groupPerm : groupPerms.entrySet()) { AclEntry.Builder builder = new AclEntry.Builder(); builder.setName(groupPerm.getKey()); builder.setType(AclEntryType.GROUP); builder.setScope(AclEntryScope.ACCESS); FsAction action = groupPerm.getValue(); if (action == FsAction.READ || action == FsAction.WRITE || action == FsAction.READ_WRITE) { action = action.or(FsAction.EXECUTE); } builder.setPermission(action); retList.add(builder.build()); } return retList; }
/** * Returns the pivot point in the list between the access entries and the * default entries. This is the index of the first element in the list that is * a default entry. * * @param aclBuilder ArrayList<AclEntry> containing entries to build * @return int pivot point, or -1 if list contains no default entries */ private static int calculatePivotOnDefaultEntries(List<AclEntry> aclBuilder) { for (int i = 0; i < aclBuilder.size(); ++i) { if (aclBuilder.get(i).getScope() == AclEntryScope.DEFAULT) { return i; } } return PIVOT_NOT_FOUND; }
@Override protected void processOptions(LinkedList<String> args) throws IOException { cf.parse(args); setRecursive(cf.getOpt("R")); // Mix of remove and modify acl flags are not allowed boolean bothRemoveOptions = cf.getOpt("b") && cf.getOpt("k"); boolean bothModifyOptions = cf.getOpt("m") && cf.getOpt("x"); boolean oneRemoveOption = cf.getOpt("b") || cf.getOpt("k"); boolean oneModifyOption = cf.getOpt("m") || cf.getOpt("x"); boolean setOption = cf.getOpt("-set"); if ((bothRemoveOptions || bothModifyOptions) || (oneRemoveOption && oneModifyOption) || (setOption && (oneRemoveOption || oneModifyOption))) { throw new HadoopIllegalArgumentException( "Specified flags contains both remove and modify flags"); } // Only -m, -x and --set expects <acl_spec> if (oneModifyOption || setOption) { if (args.size() < 2) { throw new HadoopIllegalArgumentException("<acl_spec> is missing"); } aclEntries = AclEntry.parseAclSpec(args.removeFirst(), !cf.getOpt("x")); } if (args.isEmpty()) { throw new HadoopIllegalArgumentException("<path> is missing"); } if (args.size() > 1) { throw new HadoopIllegalArgumentException("Too many arguments"); } // In recursive mode, save a separate list of just the access ACL entries. // Only directories may have a default ACL. When a recursive operation // encounters a file under the specified path, it must pass only the // access ACL entries. if (isRecursive() && (oneModifyOption || setOption)) { accessAclEntries = Lists.newArrayList(); for (AclEntry entry: aclEntries) { if (entry.getScope() == AclEntryScope.ACCESS) { accessAclEntries.add(entry); } } } }
@Test public void testMultipleAclSpecParsingWithoutPermissions() throws Exception { List<AclEntry> parsedList = AclEntry.parseAclSpec( "user::,user:user1:,group::,group:group1:,mask::,other::," + "default:user:user1::,default:mask::", false); AclEntry owner = new AclEntry.Builder().setType(AclEntryType.USER).build(); AclEntry namedUser = new AclEntry.Builder().setType(AclEntryType.USER) .setName("user1").build(); AclEntry group = new AclEntry.Builder().setType(AclEntryType.GROUP).build(); AclEntry namedGroup = new AclEntry.Builder().setType(AclEntryType.GROUP) .setName("group1").build(); AclEntry mask = new AclEntry.Builder().setType(AclEntryType.MASK).build(); AclEntry other = new AclEntry.Builder().setType(AclEntryType.OTHER).build(); AclEntry defaultUser = new AclEntry.Builder() .setScope(AclEntryScope.DEFAULT).setType(AclEntryType.USER) .setName("user1").build(); AclEntry defaultMask = new AclEntry.Builder() .setScope(AclEntryScope.DEFAULT).setType(AclEntryType.MASK).build(); List<AclEntry> expectedList = new ArrayList<AclEntry>(); expectedList.add(owner); expectedList.add(namedUser); expectedList.add(group); expectedList.add(namedGroup); expectedList.add(mask); expectedList.add(other); expectedList.add(defaultUser); expectedList.add(defaultMask); assertEquals("Parsed Acl not correct", expectedList, parsedList); }
private void check(INodeAttributes inode, String path, FsAction access ) throws AccessControlException { if (inode == null) { return; } final FsPermission mode = inode.getFsPermission(); final AclFeature aclFeature = inode.getAclFeature(); if (aclFeature != null) { // It's possible that the inode has a default ACL but no access ACL. int firstEntry = aclFeature.getEntryAt(0); if (AclEntryStatusFormat.getScope(firstEntry) == AclEntryScope.ACCESS) { checkAccessAcl(inode, path, access, mode, aclFeature); return; } } if (getUser().equals(inode.getUserName())) { //user class if (mode.getUserAction().implies(access)) { return; } } else if (getGroups().contains(inode.getGroupName())) { //group class if (mode.getGroupAction().implies(access)) { return; } } else { //other class if (mode.getOtherAction().implies(access)) { return; } } throw new AccessControlException( toAccessControlString(inode, path, access, mode)); }
/** * Filters (discards) any existing ACL entries that have the same scope, type * and name of any entry in the ACL spec. If necessary, recalculates the mask * entries. If necessary, default entries may be inferred by copying the * permissions of the corresponding access entries. It is invalid to request * removal of the mask entry from an ACL that would otherwise require a mask * entry, due to existing named entries or an unnamed group entry. * * @param existingAcl List<AclEntry> existing ACL * @param inAclSpec List<AclEntry> ACL spec describing entries to filter * @return List<AclEntry> new ACL * @throws AclException if validation fails */ public static List<AclEntry> filterAclEntriesByAclSpec( List<AclEntry> existingAcl, List<AclEntry> inAclSpec) throws AclException { ValidatedAclSpec aclSpec = new ValidatedAclSpec(inAclSpec); ArrayList<AclEntry> aclBuilder = Lists.newArrayListWithCapacity(MAX_ENTRIES); EnumMap<AclEntryScope, AclEntry> providedMask = Maps.newEnumMap(AclEntryScope.class); EnumSet<AclEntryScope> maskDirty = EnumSet.noneOf(AclEntryScope.class); EnumSet<AclEntryScope> scopeDirty = EnumSet.noneOf(AclEntryScope.class); for (AclEntry existingEntry: existingAcl) { if (aclSpec.containsKey(existingEntry)) { scopeDirty.add(existingEntry.getScope()); if (existingEntry.getType() == MASK) { maskDirty.add(existingEntry.getScope()); } } else { if (existingEntry.getType() == MASK) { providedMask.put(existingEntry.getScope(), existingEntry); } else { aclBuilder.add(existingEntry); } } } copyDefaultsIfNeeded(aclBuilder); calculateMasks(aclBuilder, providedMask, maskDirty, scopeDirty); return buildAndValidateAcl(aclBuilder); }
/** * Completely replaces the ACL with the entries of the ACL spec. If * necessary, recalculates the mask entries. If necessary, default entries * are inferred by copying the permissions of the corresponding access * entries. Replacement occurs separately for each of the access ACL and the * default ACL. If the ACL spec contains only access entries, then the * existing default entries are retained. If the ACL spec contains only * default entries, then the existing access entries are retained. If the ACL * spec contains both access and default entries, then both are replaced. * * @param existingAcl List<AclEntry> existing ACL * @param inAclSpec List<AclEntry> ACL spec containing replacement entries * @return List<AclEntry> new ACL * @throws AclException if validation fails */ public static List<AclEntry> replaceAclEntries(List<AclEntry> existingAcl, List<AclEntry> inAclSpec) throws AclException { ValidatedAclSpec aclSpec = new ValidatedAclSpec(inAclSpec); ArrayList<AclEntry> aclBuilder = Lists.newArrayListWithCapacity(MAX_ENTRIES); // Replacement is done separately for each scope: access and default. EnumMap<AclEntryScope, AclEntry> providedMask = Maps.newEnumMap(AclEntryScope.class); EnumSet<AclEntryScope> maskDirty = EnumSet.noneOf(AclEntryScope.class); EnumSet<AclEntryScope> scopeDirty = EnumSet.noneOf(AclEntryScope.class); for (AclEntry aclSpecEntry: aclSpec) { scopeDirty.add(aclSpecEntry.getScope()); if (aclSpecEntry.getType() == MASK) { providedMask.put(aclSpecEntry.getScope(), aclSpecEntry); maskDirty.add(aclSpecEntry.getScope()); } else { aclBuilder.add(aclSpecEntry); } } // Copy existing entries if the scope was not replaced. for (AclEntry existingEntry: existingAcl) { if (!scopeDirty.contains(existingEntry.getScope())) { if (existingEntry.getType() == MASK) { providedMask.put(existingEntry.getScope(), existingEntry); } else { aclBuilder.add(existingEntry); } } } copyDefaultsIfNeeded(aclBuilder); calculateMasks(aclBuilder, providedMask, maskDirty, scopeDirty); return buildAndValidateAcl(aclBuilder); }
/** * Create a new AclEntry with scope, type and permission (no name). * * @param scope AclEntryScope scope of the ACL entry * @param type AclEntryType ACL entry type * @param permission FsAction set of permissions in the ACL entry * @return AclEntry new AclEntry */ public static AclEntry aclEntry(AclEntryScope scope, AclEntryType type, FsAction permission) { return new AclEntry.Builder() .setScope(scope) .setType(type) .setPermission(permission) .build(); }
/** * Create a new AclEntry with scope, type, name and permission. * * @param scope AclEntryScope scope of the ACL entry * @param type AclEntryType ACL entry type * @param name String optional ACL entry name * @param permission FsAction set of permissions in the ACL entry * @return AclEntry new AclEntry */ public static AclEntry aclEntry(AclEntryScope scope, AclEntryType type, String name, FsAction permission) { return new AclEntry.Builder() .setScope(scope) .setType(type) .setName(name) .setPermission(permission) .build(); }
/** * Create a new AclEntry with scope, type and name (no permission). * * @param scope AclEntryScope scope of the ACL entry * @param type AclEntryType ACL entry type * @param name String optional ACL entry name * @return AclEntry new AclEntry */ public static AclEntry aclEntry(AclEntryScope scope, AclEntryType type, String name) { return new AclEntry.Builder() .setScope(scope) .setType(type) .setName(name) .build(); }
@Test public void testAclStatusProto() { AclEntry e = new AclEntry.Builder().setName("test") .setPermission(FsAction.READ_EXECUTE).setScope(AclEntryScope.DEFAULT) .setType(AclEntryType.OTHER).build(); AclStatus s = new AclStatus.Builder().owner("foo").group("bar").addEntry(e) .build(); Assert.assertEquals(s, PBHelper.convert(PBHelper.convert(s))); }
/** * Create a new AclEntry with scope, type and permission (no name). * * @param scope AclEntryScope scope of the ACL entry * @param type AclEntryType ACL entry type * @param permission FsAction set of permissions in the ACL entry * @return AclEntry new AclEntry */ private static AclEntry aclEntry(AclEntryScope scope, AclEntryType type, FsAction permission) { return new AclEntry.Builder() .setScope(scope) .setType(type) .setPermission(permission) .build(); }
/** * Create a new AclEntry with scope, type, name and permission. * * @param scope AclEntryScope scope of the ACL entry * @param type AclEntryType ACL entry type * @param name String optional ACL entry name * @param permission FsAction set of permissions in the ACL entry * @return AclEntry new AclEntry */ private static AclEntry aclEntry(AclEntryScope scope, AclEntryType type, String name, FsAction permission) { return new AclEntry.Builder() .setScope(scope) .setType(type) .setName(name) .setPermission(permission) .build(); }