1 /** 2 * Licensed to the Apache Software Foundation (ASF) under one 3 * or more contributor license agreements. See the NOTICE file 4 * distributed with this work for additional information 5 * regarding copyright ownership. The ASF licenses this file 6 * to you under the Apache License, Version 2.0 (the 7 * "License"); you may not use this file except in compliance 8 * with the License. You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, software 13 * distributed under the License is distributed on an "AS IS" BASIS, 14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 * See the License for the specific language governing permissions and 16 * limitations under the License. 17 */ 18 package org.apache.hadoop.hdfs.server.namenode; 19 20 import java.io.IOException; 21 import java.security.PrivilegedExceptionAction; 22 import java.util.HashSet; 23 import java.util.Map; 24 import java.util.Set; 25 26 import com.google.common.collect.ImmutableList; 27 import org.apache.hadoop.conf.Configuration; 28 import org.apache.hadoop.fs.FileStatus; 29 import org.apache.hadoop.fs.FileSystem; 30 import org.apache.hadoop.fs.Path; 31 import org.apache.hadoop.fs.XAttr; 32 import org.apache.hadoop.fs.permission.*; 33 import org.apache.hadoop.hdfs.DFSConfigKeys; 34 import org.apache.hadoop.hdfs.HdfsConfiguration; 35 import org.apache.hadoop.hdfs.MiniDFSCluster; 36 import org.apache.hadoop.hdfs.server.namenode.INodeAttributeProvider.AccessControlEnforcer; 37 import org.apache.hadoop.security.AccessControlException; 38 import org.apache.hadoop.security.UserGroupInformation; 39 import org.junit.After; 40 import org.junit.Assert; 41 import org.junit.Before; 42 import org.junit.Test; 43 44 import com.google.common.collect.Lists; 45 46 public class TestINodeAttributeProvider { 47 private MiniDFSCluster miniDFS; 48 private static final Set<String> CALLED = new HashSet<String>(); 49 50 public static class MyAuthorizationProvider extends INodeAttributeProvider { 51 52 public static class MyAccessControlEnforcer implements AccessControlEnforcer { 53 54 @Override 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)55 public void checkPermission(String fsOwner, String supergroup, 56 UserGroupInformation ugi, INodeAttributes[] inodeAttrs, 57 INode[] inodes, byte[][] pathByNameArr, int snapshotId, String path, 58 int ancestorIndex, boolean doCheckOwner, FsAction ancestorAccess, 59 FsAction parentAccess, FsAction access, FsAction subAccess, 60 boolean ignoreEmptyDir) throws AccessControlException { 61 CALLED.add("checkPermission|" + ancestorAccess + "|" + parentAccess + "|" + access); 62 } 63 } 64 65 @Override start()66 public void start() { 67 CALLED.add("start"); 68 } 69 70 @Override stop()71 public void stop() { 72 CALLED.add("stop"); 73 } 74 75 @Override getAttributes(String[] pathElements, final INodeAttributes inode)76 public INodeAttributes getAttributes(String[] pathElements, 77 final INodeAttributes inode) { 78 CALLED.add("getAttributes"); 79 final boolean useDefault = useDefault(pathElements); 80 return new INodeAttributes() { 81 @Override 82 public boolean isDirectory() { 83 return inode.isDirectory(); 84 } 85 86 @Override 87 public byte[] getLocalNameBytes() { 88 return inode.getLocalNameBytes(); 89 } 90 91 @Override 92 public String getUserName() { 93 return (useDefault) ? inode.getUserName() : "foo"; 94 } 95 96 @Override 97 public String getGroupName() { 98 return (useDefault) ? inode.getGroupName() : "bar"; 99 } 100 101 @Override 102 public FsPermission getFsPermission() { 103 return (useDefault) ? inode.getFsPermission() 104 : new FsPermission(getFsPermissionShort()); 105 } 106 107 @Override 108 public short getFsPermissionShort() { 109 return (useDefault) ? inode.getFsPermissionShort() 110 : (short) getPermissionLong(); 111 } 112 113 @Override 114 public long getPermissionLong() { 115 return (useDefault) ? inode.getPermissionLong() : 0770; 116 } 117 118 @Override 119 public AclFeature getAclFeature() { 120 AclFeature f; 121 if (useDefault) { 122 f = inode.getAclFeature(); 123 } else { 124 AclEntry acl = new AclEntry.Builder().setType(AclEntryType.GROUP). 125 setPermission(FsAction.ALL).setName("xxx").build(); 126 f = new AclFeature(AclEntryStatusFormat.toInt( 127 Lists.newArrayList(acl))); 128 } 129 return f; 130 } 131 132 @Override 133 public XAttrFeature getXAttrFeature() { 134 XAttrFeature x; 135 if (useDefault) { 136 x = inode.getXAttrFeature(); 137 } else { 138 x = new XAttrFeature(ImmutableList.copyOf( 139 Lists.newArrayList( 140 new XAttr.Builder().setName("test") 141 .setValue(new byte[] {1, 2}) 142 .build()))); 143 } 144 return x; 145 } 146 147 @Override 148 public long getModificationTime() { 149 return (useDefault) ? inode.getModificationTime() : 0; 150 } 151 152 @Override 153 public long getAccessTime() { 154 return (useDefault) ? inode.getAccessTime() : 0; 155 } 156 }; 157 158 } 159 160 @Override getExternalAccessControlEnforcer( AccessControlEnforcer deafultEnforcer)161 public AccessControlEnforcer getExternalAccessControlEnforcer( 162 AccessControlEnforcer deafultEnforcer) { 163 return new MyAccessControlEnforcer(); 164 } 165 useDefault(String[] pathElements)166 private boolean useDefault(String[] pathElements) { 167 return (pathElements.length < 2) || 168 !(pathElements[0].equals("user") && pathElements[1].equals("authz")); 169 } 170 171 } 172 173 @Before 174 public void setUp() throws IOException { 175 CALLED.clear(); 176 Configuration conf = new HdfsConfiguration(); 177 conf.set(DFSConfigKeys.DFS_NAMENODE_INODE_ATTRIBUTES_PROVIDER_KEY, 178 MyAuthorizationProvider.class.getName()); 179 conf.setBoolean(DFSConfigKeys.DFS_NAMENODE_ACLS_ENABLED_KEY, true); 180 EditLogFileOutputStream.setShouldSkipFsyncForTesting(true); 181 miniDFS = new MiniDFSCluster.Builder(conf).build(); 182 } 183 184 @After 185 public void cleanUp() throws IOException { 186 CALLED.clear(); 187 if (miniDFS != null) { 188 miniDFS.shutdown(); 189 } 190 Assert.assertTrue(CALLED.contains("stop")); 191 } 192 193 @Test 194 public void testDelegationToProvider() throws Exception { 195 Assert.assertTrue(CALLED.contains("start")); 196 FileSystem fs = FileSystem.get(miniDFS.getConfiguration(0)); 197 fs.mkdirs(new Path("/tmp")); 198 fs.setPermission(new Path("/tmp"), new FsPermission((short) 0777)); 199 UserGroupInformation ugi = UserGroupInformation.createUserForTesting("u1", 200 new String[]{"g1"}); 201 ugi.doAs(new PrivilegedExceptionAction<Void>() { 202 @Override 203 public Void run() throws Exception { 204 FileSystem fs = FileSystem.get(miniDFS.getConfiguration(0)); 205 CALLED.clear(); 206 fs.mkdirs(new Path("/tmp/foo")); 207 Assert.assertTrue(CALLED.contains("getAttributes")); 208 Assert.assertTrue(CALLED.contains("checkPermission|null|null|null")); 209 Assert.assertTrue(CALLED.contains("checkPermission|WRITE|null|null")); 210 CALLED.clear(); 211 fs.listStatus(new Path("/tmp/foo")); 212 Assert.assertTrue(CALLED.contains("getAttributes")); 213 Assert.assertTrue( 214 CALLED.contains("checkPermission|null|null|READ_EXECUTE")); 215 CALLED.clear(); 216 fs.getAclStatus(new Path("/tmp/foo")); 217 Assert.assertTrue(CALLED.contains("getAttributes")); 218 Assert.assertTrue(CALLED.contains("checkPermission|null|null|null")); 219 return null; 220 } 221 }); 222 } 223 224 @Test 225 public void testCustomProvider() throws Exception { 226 FileSystem fs = FileSystem.get(miniDFS.getConfiguration(0)); 227 fs.mkdirs(new Path("/user/xxx")); 228 FileStatus status = fs.getFileStatus(new Path("/user/xxx")); 229 Assert.assertEquals(System.getProperty("user.name"), status.getOwner()); 230 Assert.assertEquals("supergroup", status.getGroup()); 231 Assert.assertEquals(new FsPermission((short) 0755), status.getPermission()); 232 fs.mkdirs(new Path("/user/authz")); 233 Path p = new Path("/user/authz"); 234 status = fs.getFileStatus(p); 235 Assert.assertEquals("foo", status.getOwner()); 236 Assert.assertEquals("bar", status.getGroup()); 237 Assert.assertEquals(new FsPermission((short) 0770), status.getPermission()); 238 AclStatus aclStatus = fs.getAclStatus(p); 239 Assert.assertEquals(1, aclStatus.getEntries().size()); 240 Assert.assertEquals(AclEntryType.GROUP, aclStatus.getEntries().get(0) 241 .getType()); 242 Assert.assertEquals("xxx", aclStatus.getEntries().get(0) 243 .getName()); 244 Assert.assertEquals(FsAction.ALL, aclStatus.getEntries().get(0) 245 .getPermission()); 246 Map<String, byte[]> xAttrs = fs.getXAttrs(p); 247 Assert.assertTrue(xAttrs.containsKey("user.test")); 248 Assert.assertEquals(2, xAttrs.get("user.test").length); 249 } 250 251 } 252