| /** |
| * 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 |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * 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.hdfs.server.namenode; |
| |
| import java.io.IOException; |
| import java.security.PrivilegedExceptionAction; |
| import java.util.HashSet; |
| import java.util.Map; |
| import java.util.Set; |
| |
| import com.google.common.collect.ImmutableList; |
| import org.apache.hadoop.conf.Configuration; |
| import org.apache.hadoop.fs.FileStatus; |
| import org.apache.hadoop.fs.FileSystem; |
| import org.apache.hadoop.fs.Path; |
| import org.apache.hadoop.fs.XAttr; |
| import org.apache.hadoop.fs.permission.*; |
| import org.apache.hadoop.hdfs.DFSConfigKeys; |
| import org.apache.hadoop.hdfs.HdfsConfiguration; |
| import org.apache.hadoop.hdfs.MiniDFSCluster; |
| import org.apache.hadoop.hdfs.server.namenode.INodeAttributeProvider.AccessControlEnforcer; |
| import org.apache.hadoop.security.AccessControlException; |
| import org.apache.hadoop.security.UserGroupInformation; |
| import org.junit.After; |
| import org.junit.Assert; |
| import org.junit.Before; |
| import org.junit.Test; |
| |
| import com.google.common.collect.Lists; |
| |
| public class TestINodeAttributeProvider { |
| private MiniDFSCluster miniDFS; |
| private static final Set<String> CALLED = new HashSet<String>(); |
| |
| public static class MyAuthorizationProvider extends INodeAttributeProvider { |
| |
| public static class MyAccessControlEnforcer implements AccessControlEnforcer { |
| |
| @Override |
| public void checkPermission(String fsOwner, String supergroup, |
| UserGroupInformation ugi, INodeAttributes[] inodeAttrs, |
| INode[] inodes, byte[][] pathByNameArr, int snapshotId, String path, |
| int ancestorIndex, boolean doCheckOwner, FsAction ancestorAccess, |
| FsAction parentAccess, FsAction access, FsAction subAccess, |
| boolean ignoreEmptyDir) throws AccessControlException { |
| CALLED.add("checkPermission|" + ancestorAccess + "|" + parentAccess + "|" + access); |
| } |
| } |
| |
| @Override |
| public void start() { |
| CALLED.add("start"); |
| } |
| |
| @Override |
| public void stop() { |
| CALLED.add("stop"); |
| } |
| |
| @Override |
| public INodeAttributes getAttributes(String[] pathElements, |
| final INodeAttributes inode) { |
| CALLED.add("getAttributes"); |
| final boolean useDefault = useDefault(pathElements); |
| return new INodeAttributes() { |
| @Override |
| public boolean isDirectory() { |
| return inode.isDirectory(); |
| } |
| |
| @Override |
| public byte[] getLocalNameBytes() { |
| return inode.getLocalNameBytes(); |
| } |
| |
| @Override |
| public String getUserName() { |
| return (useDefault) ? inode.getUserName() : "foo"; |
| } |
| |
| @Override |
| public String getGroupName() { |
| return (useDefault) ? inode.getGroupName() : "bar"; |
| } |
| |
| @Override |
| public FsPermission getFsPermission() { |
| return (useDefault) ? inode.getFsPermission() |
| : new FsPermission(getFsPermissionShort()); |
| } |
| |
| @Override |
| public short getFsPermissionShort() { |
| return (useDefault) ? inode.getFsPermissionShort() |
| : (short) getPermissionLong(); |
| } |
| |
| @Override |
| public long getPermissionLong() { |
| return (useDefault) ? inode.getPermissionLong() : 0770; |
| } |
| |
| @Override |
| public AclFeature getAclFeature() { |
| AclFeature f; |
| if (useDefault) { |
| f = inode.getAclFeature(); |
| } else { |
| AclEntry acl = new AclEntry.Builder().setType(AclEntryType.GROUP). |
| setPermission(FsAction.ALL).setName("xxx").build(); |
| f = new AclFeature(AclEntryStatusFormat.toInt( |
| Lists.newArrayList(acl))); |
| } |
| return f; |
| } |
| |
| @Override |
| public XAttrFeature getXAttrFeature() { |
| XAttrFeature x; |
| if (useDefault) { |
| x = inode.getXAttrFeature(); |
| } else { |
| x = new XAttrFeature(ImmutableList.copyOf( |
| Lists.newArrayList( |
| new XAttr.Builder().setName("test") |
| .setValue(new byte[] {1, 2}) |
| .build()))); |
| } |
| return x; |
| } |
| |
| @Override |
| public long getModificationTime() { |
| return (useDefault) ? inode.getModificationTime() : 0; |
| } |
| |
| @Override |
| public long getAccessTime() { |
| return (useDefault) ? inode.getAccessTime() : 0; |
| } |
| }; |
| |
| } |
| |
| @Override |
| public AccessControlEnforcer getExternalAccessControlEnforcer( |
| AccessControlEnforcer deafultEnforcer) { |
| return new MyAccessControlEnforcer(); |
| } |
| |
| private boolean useDefault(String[] pathElements) { |
| return (pathElements.length < 2) || |
| !(pathElements[0].equals("user") && pathElements[1].equals("authz")); |
| } |
| |
| } |
| |
| @Before |
| public void setUp() throws IOException { |
| CALLED.clear(); |
| Configuration conf = new HdfsConfiguration(); |
| conf.set(DFSConfigKeys.DFS_NAMENODE_INODE_ATTRIBUTES_PROVIDER_KEY, |
| MyAuthorizationProvider.class.getName()); |
| conf.setBoolean(DFSConfigKeys.DFS_NAMENODE_ACLS_ENABLED_KEY, true); |
| EditLogFileOutputStream.setShouldSkipFsyncForTesting(true); |
| miniDFS = new MiniDFSCluster.Builder(conf).build(); |
| } |
| |
| @After |
| public void cleanUp() throws IOException { |
| CALLED.clear(); |
| if (miniDFS != null) { |
| miniDFS.shutdown(); |
| } |
| Assert.assertTrue(CALLED.contains("stop")); |
| } |
| |
| @Test |
| public void testDelegationToProvider() throws Exception { |
| Assert.assertTrue(CALLED.contains("start")); |
| FileSystem fs = FileSystem.get(miniDFS.getConfiguration(0)); |
| fs.mkdirs(new Path("/tmp")); |
| fs.setPermission(new Path("/tmp"), new FsPermission((short) 0777)); |
| UserGroupInformation ugi = UserGroupInformation.createUserForTesting("u1", |
| new String[]{"g1"}); |
| ugi.doAs(new PrivilegedExceptionAction<Void>() { |
| @Override |
| public Void run() throws Exception { |
| FileSystem fs = FileSystem.get(miniDFS.getConfiguration(0)); |
| CALLED.clear(); |
| fs.mkdirs(new Path("/tmp/foo")); |
| Assert.assertTrue(CALLED.contains("getAttributes")); |
| Assert.assertTrue(CALLED.contains("checkPermission|null|null|null")); |
| Assert.assertTrue(CALLED.contains("checkPermission|WRITE|null|null")); |
| CALLED.clear(); |
| fs.listStatus(new Path("/tmp/foo")); |
| Assert.assertTrue(CALLED.contains("getAttributes")); |
| Assert.assertTrue( |
| CALLED.contains("checkPermission|null|null|READ_EXECUTE")); |
| CALLED.clear(); |
| fs.getAclStatus(new Path("/tmp/foo")); |
| Assert.assertTrue(CALLED.contains("getAttributes")); |
| Assert.assertTrue(CALLED.contains("checkPermission|null|null|null")); |
| return null; |
| } |
| }); |
| } |
| |
| @Test |
| public void testCustomProvider() throws Exception { |
| FileSystem fs = FileSystem.get(miniDFS.getConfiguration(0)); |
| fs.mkdirs(new Path("/user/xxx")); |
| FileStatus status = fs.getFileStatus(new Path("/user/xxx")); |
| Assert.assertEquals(System.getProperty("user.name"), status.getOwner()); |
| Assert.assertEquals("supergroup", status.getGroup()); |
| Assert.assertEquals(new FsPermission((short) 0755), status.getPermission()); |
| fs.mkdirs(new Path("/user/authz")); |
| Path p = new Path("/user/authz"); |
| status = fs.getFileStatus(p); |
| Assert.assertEquals("foo", status.getOwner()); |
| Assert.assertEquals("bar", status.getGroup()); |
| Assert.assertEquals(new FsPermission((short) 0770), status.getPermission()); |
| AclStatus aclStatus = fs.getAclStatus(p); |
| Assert.assertEquals(1, aclStatus.getEntries().size()); |
| Assert.assertEquals(AclEntryType.GROUP, aclStatus.getEntries().get(0) |
| .getType()); |
| Assert.assertEquals("xxx", aclStatus.getEntries().get(0) |
| .getName()); |
| Assert.assertEquals(FsAction.ALL, aclStatus.getEntries().get(0) |
| .getPermission()); |
| Map<String, byte[]> xAttrs = fs.getXAttrs(p); |
| Assert.assertTrue(xAttrs.containsKey("user.test")); |
| Assert.assertEquals(2, xAttrs.get("user.test").length); |
| } |
| |
| } |