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 
19 package org.apache.hadoop.fs;
20 
21 import java.io.IOException;
22 import java.net.URISyntaxException;
23 
24 import javax.security.auth.login.LoginException;
25 
26 import org.apache.hadoop.conf.Configuration;
27 import org.apache.hadoop.fs.permission.FsPermission;
28 import org.apache.hadoop.fs.CommonConfigurationKeys;
29 import org.apache.hadoop.hdfs.HdfsConfiguration;
30 import org.apache.hadoop.hdfs.MiniDFSCluster;
31 import org.apache.hadoop.security.UserGroupInformation;
32 import org.apache.hadoop.util.StringUtils;
33 import static org.apache.hadoop.fs.FileContextTestHelper.*;
34 import org.apache.commons.logging.impl.Log4JLogger;
35 import org.apache.log4j.Level;
36 import org.junit.After;
37 import org.junit.AfterClass;
38 import org.junit.Assert;
39 import org.junit.Before;
40 import org.junit.BeforeClass;
41 import org.junit.Test;
42 
43 public class TestFcHdfsSetUMask {
44 
45   private static final FileContextTestHelper fileContextTestHelper =
46       new FileContextTestHelper("/tmp/TestFcHdfsSetUMask");
47   private static MiniDFSCluster cluster;
48   private static Path defaultWorkingDirectory;
49   private static FileContext fc;
50 
51   // rwxrwx---
52   private static final FsPermission USER_GROUP_OPEN_PERMISSIONS = FsPermission
53       .createImmutable((short) 0770);
54 
55   private static final FsPermission USER_GROUP_OPEN_FILE_PERMISSIONS =
56       FsPermission.createImmutable((short) 0660);
57 
58   private static final FsPermission USER_GROUP_OPEN_TEST_UMASK = FsPermission
59       .createImmutable((short) (0770 ^ 0777));
60 
61   // ---------
62   private static final FsPermission BLANK_PERMISSIONS = FsPermission
63       .createImmutable((short) 0000);
64 
65   // parent directory permissions when creating a directory with blank (000)
66   // permissions - it always add the -wx------ bits to the parent so that
67   // it can create the child
68   private static final FsPermission PARENT_PERMS_FOR_BLANK_PERMISSIONS =
69       FsPermission.createImmutable((short) 0300);
70 
71   private static final FsPermission BLANK_TEST_UMASK = FsPermission
72       .createImmutable((short) (0000 ^ 0777));
73 
74   // rwxrwxrwx
75   private static final FsPermission WIDE_OPEN_PERMISSIONS = FsPermission
76       .createImmutable((short) 0777);
77 
78   private static final FsPermission WIDE_OPEN_FILE_PERMISSIONS =
79       FsPermission.createImmutable((short) 0666);
80 
81   private static final FsPermission WIDE_OPEN_TEST_UMASK = FsPermission
82       .createImmutable((short) (0777 ^ 0777));
83 
84   @BeforeClass
clusterSetupAtBegining()85   public static void clusterSetupAtBegining()
86         throws IOException, LoginException, URISyntaxException  {
87     Configuration conf = new HdfsConfiguration();
88     // set permissions very restrictive
89     conf.set(CommonConfigurationKeys.FS_PERMISSIONS_UMASK_KEY,  "077");
90     cluster = new MiniDFSCluster.Builder(conf).numDataNodes(2).build();
91     fc = FileContext.getFileContext(cluster.getURI(0), conf);
92     defaultWorkingDirectory = fc.makeQualified( new Path("/user/" +
93         UserGroupInformation.getCurrentUser().getShortUserName()));
94     fc.mkdir(defaultWorkingDirectory, FileContext.DEFAULT_PERM, true);
95   }
96 
97   @AfterClass
ClusterShutdownAtEnd()98   public static void ClusterShutdownAtEnd() throws Exception {
99     cluster.shutdown();
100   }
101 
102   {
103     try {
104       ((Log4JLogger)FileSystem.LOG).getLogger().setLevel(Level.DEBUG);
105     }
106     catch(Exception e) {
107       System.out.println("Cannot change log level\n"
108           + StringUtils.stringifyException(e));
109     }
110   }
111 
112   @Before
setUp()113   public void setUp() throws Exception {
114     fc.setUMask(WIDE_OPEN_TEST_UMASK);
115     fc.mkdir(fileContextTestHelper.getTestRootPath(fc), FileContext.DEFAULT_PERM, true);
116   }
117 
118   @After
tearDown()119   public void tearDown() throws Exception {
120     fc.delete(fileContextTestHelper.getTestRootPath(fc), true);
121   }
122 
123   @Test
testMkdirWithExistingDirClear()124   public void testMkdirWithExistingDirClear() throws IOException {
125     testMkdirWithExistingDir(BLANK_TEST_UMASK, BLANK_PERMISSIONS);
126   }
127 
128   @Test
testMkdirWithExistingDirOpen()129   public void testMkdirWithExistingDirOpen() throws IOException {
130     testMkdirWithExistingDir(WIDE_OPEN_TEST_UMASK, WIDE_OPEN_PERMISSIONS);
131   }
132 
133   @Test
testMkdirWithExistingDirMiddle()134   public void testMkdirWithExistingDirMiddle() throws IOException {
135     testMkdirWithExistingDir(USER_GROUP_OPEN_TEST_UMASK,
136         USER_GROUP_OPEN_PERMISSIONS);
137   }
138 
139   @Test
testMkdirRecursiveWithNonExistingDirClear()140   public void testMkdirRecursiveWithNonExistingDirClear() throws IOException {
141     // by default parent directories have -wx------ bits set
142     testMkdirRecursiveWithNonExistingDir(BLANK_TEST_UMASK, BLANK_PERMISSIONS,
143         PARENT_PERMS_FOR_BLANK_PERMISSIONS);
144   }
145 
146   @Test
testMkdirRecursiveWithNonExistingDirOpen()147   public void testMkdirRecursiveWithNonExistingDirOpen() throws IOException {
148     testMkdirRecursiveWithNonExistingDir(WIDE_OPEN_TEST_UMASK,
149         WIDE_OPEN_PERMISSIONS, WIDE_OPEN_PERMISSIONS);
150   }
151 
152   @Test
testMkdirRecursiveWithNonExistingDirMiddle()153   public void testMkdirRecursiveWithNonExistingDirMiddle() throws IOException {
154     testMkdirRecursiveWithNonExistingDir(USER_GROUP_OPEN_TEST_UMASK,
155         USER_GROUP_OPEN_PERMISSIONS, USER_GROUP_OPEN_PERMISSIONS);
156   }
157 
158 
159   @Test
testCreateRecursiveWithExistingDirClear()160   public void testCreateRecursiveWithExistingDirClear() throws IOException {
161     testCreateRecursiveWithExistingDir(BLANK_TEST_UMASK, BLANK_PERMISSIONS);
162   }
163 
164   @Test
testCreateRecursiveWithExistingDirOpen()165   public void testCreateRecursiveWithExistingDirOpen() throws IOException {
166     testCreateRecursiveWithExistingDir(WIDE_OPEN_TEST_UMASK,
167         WIDE_OPEN_FILE_PERMISSIONS);
168   }
169 
170   @Test
testCreateRecursiveWithExistingDirMiddle()171   public void testCreateRecursiveWithExistingDirMiddle() throws IOException {
172     testCreateRecursiveWithExistingDir(USER_GROUP_OPEN_TEST_UMASK,
173         USER_GROUP_OPEN_FILE_PERMISSIONS);
174   }
175 
176 
177   @Test
testCreateRecursiveWithNonExistingDirClear()178   public void testCreateRecursiveWithNonExistingDirClear() throws IOException {
179     // directory permission inherited from parent so this must match the @Before
180     // set of umask
181     testCreateRecursiveWithNonExistingDir(BLANK_TEST_UMASK,
182         WIDE_OPEN_PERMISSIONS, BLANK_PERMISSIONS);
183   }
184 
185   @Test
testCreateRecursiveWithNonExistingDirOpen()186   public void testCreateRecursiveWithNonExistingDirOpen() throws IOException {
187     // directory permission inherited from parent so this must match the @Before
188     // set of umask
189     testCreateRecursiveWithNonExistingDir(WIDE_OPEN_TEST_UMASK,
190         WIDE_OPEN_PERMISSIONS, WIDE_OPEN_FILE_PERMISSIONS);
191   }
192 
193   @Test
testCreateRecursiveWithNonExistingDirMiddle()194   public void testCreateRecursiveWithNonExistingDirMiddle() throws IOException {
195     // directory permission inherited from parent so this must match the @Before
196     // set of umask
197     testCreateRecursiveWithNonExistingDir(USER_GROUP_OPEN_TEST_UMASK,
198         WIDE_OPEN_PERMISSIONS, USER_GROUP_OPEN_FILE_PERMISSIONS);
199   }
200 
201 
testMkdirWithExistingDir(FsPermission umask, FsPermission expectedPerms)202   public void testMkdirWithExistingDir(FsPermission umask,
203       FsPermission expectedPerms) throws IOException {
204     Path f = fileContextTestHelper.getTestRootPath(fc, "aDir");
205     fc.setUMask(umask);
206     fc.mkdir(f, FileContext.DEFAULT_PERM, true);
207     Assert.assertTrue(isDir(fc, f));
208     Assert.assertEquals("permissions on directory are wrong",
209         expectedPerms, fc.getFileStatus(f).getPermission());
210   }
211 
testMkdirRecursiveWithNonExistingDir(FsPermission umask, FsPermission expectedPerms, FsPermission expectedParentPerms)212   public void testMkdirRecursiveWithNonExistingDir(FsPermission umask,
213       FsPermission expectedPerms, FsPermission expectedParentPerms)
214       throws IOException {
215     Path f = fileContextTestHelper.getTestRootPath(fc, "NonExistant2/aDir");
216     fc.setUMask(umask);
217     fc.mkdir(f, FileContext.DEFAULT_PERM, true);
218     Assert.assertTrue(isDir(fc, f));
219     Assert.assertEquals("permissions on directory are wrong",
220         expectedPerms, fc.getFileStatus(f).getPermission());
221     Path fParent = fileContextTestHelper.getTestRootPath(fc, "NonExistant2");
222     Assert.assertEquals("permissions on parent directory are wrong",
223         expectedParentPerms, fc.getFileStatus(fParent).getPermission());
224   }
225 
226 
testCreateRecursiveWithExistingDir(FsPermission umask, FsPermission expectedPerms)227   public void testCreateRecursiveWithExistingDir(FsPermission umask,
228       FsPermission expectedPerms) throws IOException {
229     Path f = fileContextTestHelper.getTestRootPath(fc,"foo");
230     fc.setUMask(umask);
231     createFile(fc, f);
232     Assert.assertTrue(isFile(fc, f));
233     Assert.assertEquals("permissions on file are wrong",
234         expectedPerms , fc.getFileStatus(f).getPermission());
235   }
236 
237 
testCreateRecursiveWithNonExistingDir(FsPermission umask, FsPermission expectedDirPerms, FsPermission expectedFilePerms)238   public void testCreateRecursiveWithNonExistingDir(FsPermission umask,
239       FsPermission expectedDirPerms, FsPermission expectedFilePerms)
240       throws IOException {
241     Path f = fileContextTestHelper.getTestRootPath(fc,"NonExisting/foo");
242     Path fParent = fileContextTestHelper.getTestRootPath(fc, "NonExisting");
243     Assert.assertFalse(exists(fc, fParent));
244     fc.setUMask(umask);
245     createFile(fc, f);
246     Assert.assertTrue(isFile(fc, f));
247     Assert.assertEquals("permissions on file are wrong",
248         expectedFilePerms, fc.getFileStatus(f).getPermission());
249     Assert.assertEquals("permissions on parent directory are wrong",
250         expectedDirPerms, fc.getFileStatus(fParent).getPermission());
251   }
252 
253 }
254