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.fs;
19 
20 import java.io.IOException;
21 import java.security.PrivilegedExceptionAction;
22 import java.util.ArrayList;
23 import java.util.List;
24 import java.util.StringTokenizer;
25 
26 import org.junit.Assert;
27 
28 import org.apache.hadoop.fs.permission.FsPermission;
29 import org.apache.hadoop.security.UserGroupInformation;
30 import org.apache.hadoop.util.Shell;
31 import org.apache.hadoop.util.StringUtils;
32 import org.junit.After;
33 import org.junit.Before;
34 import org.junit.Test;
35 
36 import static org.apache.hadoop.fs.FileContextTestHelper.*;
37 import static org.junit.Assert.assertEquals;
38 import static org.junit.Assert.fail;
39 
40 /**
41  * <p>
42  * A collection of permission tests for the {@link FileContext}.
43  * This test should be used for testing an instance of FileContext
44  *  that has been initialized to a specific default FileSystem such a
45  *  LocalFileSystem, HDFS,S3, etc.
46  * </p>
47  * <p>
48  * To test a given {@link FileSystem} implementation create a subclass of this
49  * test and override {@link #setUp()} to initialize the <code>fc</code>
50  * {@link FileContext} instance variable.
51  *
52  * Since this a junit 4 you can also do a single setup before
53  * the start of any tests.
54  * E.g.
55  *     @BeforeClass   public static void clusterSetupAtBegining()
56  *     @AfterClass    public static void ClusterShutdownAtEnd()
57  * </p>
58  */
59 public abstract class FileContextPermissionBase {
60 
61   {
62     try {
63       ((org.apache.commons.logging.impl.Log4JLogger)FileSystem.LOG).getLogger()
64       .setLevel(org.apache.log4j.Level.DEBUG);
65     }
66     catch(Exception e) {
67       System.out.println("Cannot change log level\n"
68           + StringUtils.stringifyException(e));
69     }
70   }
71 
72   protected FileContextTestHelper fileContextTestHelper;
73   protected FileContext fc;
74 
getFileContextHelper()75   protected FileContextTestHelper getFileContextHelper() {
76       return new FileContextTestHelper();
77   }
78 
getFileContext()79   protected abstract FileContext getFileContext() throws Exception;
80 
81   @Before
setUp()82   public void setUp() throws Exception {
83     fileContextTestHelper = getFileContextHelper();
84     fc = getFileContext();
85     fc.mkdir(fileContextTestHelper.getTestRootPath(fc), FileContext.DEFAULT_PERM, true);
86   }
87 
88   @After
tearDown()89   public void tearDown() throws Exception {
90     fc.delete(fileContextTestHelper.getTestRootPath(fc), true);
91   }
92 
cleanupFile(FileContext fc, Path name)93   private void cleanupFile(FileContext fc, Path name) throws IOException {
94     Assert.assertTrue(exists(fc, name));
95     fc.delete(name, true);
96     Assert.assertTrue(!exists(fc, name));
97   }
98 
99   @Test
testCreatePermission()100   public void testCreatePermission() throws IOException {
101     if (Path.WINDOWS) {
102       System.out.println("Cannot run test for Windows");
103       return;
104     }
105     String filename = "foo";
106     Path f = fileContextTestHelper.getTestRootPath(fc, filename);
107     fileContextTestHelper.createFile(fc, filename);
108     doFilePermissionCheck(FileContext.FILE_DEFAULT_PERM.applyUMask(fc.getUMask()),
109                         fc.getFileStatus(f).getPermission());
110   }
111 
112 
113   @Test
testSetPermission()114   public void testSetPermission() throws IOException {
115     if (Path.WINDOWS) {
116       System.out.println("Cannot run test for Windows");
117       return;
118     }
119 
120     String filename = "foo";
121     Path f = fileContextTestHelper.getTestRootPath(fc, filename);
122     createFile(fc, f);
123 
124     try {
125       // create files and manipulate them.
126       FsPermission all = new FsPermission((short)0777);
127       FsPermission none = new FsPermission((short)0);
128 
129       fc.setPermission(f, none);
130       doFilePermissionCheck(none, fc.getFileStatus(f).getPermission());
131 
132       fc.setPermission(f, all);
133       doFilePermissionCheck(all, fc.getFileStatus(f).getPermission());
134     }
135     finally {cleanupFile(fc, f);}
136   }
137 
138   @Test
testSetOwner()139   public void testSetOwner() throws IOException {
140     if (Path.WINDOWS) {
141       System.out.println("Cannot run test for Windows");
142       return;
143     }
144 
145     String filename = "bar";
146     Path f = fileContextTestHelper.getTestRootPath(fc, filename);
147     createFile(fc, f);
148     List<String> groups = null;
149     try {
150       groups = getGroups();
151       System.out.println(filename + ": " + fc.getFileStatus(f).getPermission());
152     }
153     catch(IOException e) {
154       System.out.println(StringUtils.stringifyException(e));
155       System.out.println("Cannot run test");
156       return;
157     }
158     if (groups == null || groups.size() < 1) {
159       System.out.println("Cannot run test: need at least one group.  groups="
160                          + groups);
161       return;
162     }
163 
164     // create files and manipulate them.
165     try {
166       String g0 = groups.get(0);
167       fc.setOwner(f, null, g0);
168       Assert.assertEquals(g0, fc.getFileStatus(f).getGroup());
169 
170       if (groups.size() > 1) {
171         String g1 = groups.get(1);
172         fc.setOwner(f, null, g1);
173         Assert.assertEquals(g1, fc.getFileStatus(f).getGroup());
174       } else {
175         System.out.println("Not testing changing the group since user " +
176                            "belongs to only one group.");
177       }
178 
179       try {
180         fc.setOwner(f, null, null);
181         fail("Exception expected.");
182       } catch (IllegalArgumentException iae) {
183         // okay
184       }
185     }
186     finally {cleanupFile(fc, f);}
187   }
188 
189   @Test
testUgi()190   public void testUgi() throws IOException, InterruptedException {
191 
192     UserGroupInformation otherUser = UserGroupInformation
193         .createRemoteUser("otherUser");
194     FileContext newFc = otherUser.doAs(new PrivilegedExceptionAction<FileContext>() {
195 
196       @Override
197       public FileContext run() throws Exception {
198         FileContext newFc = FileContext.getFileContext();
199         return newFc;
200       }
201 
202     });
203     assertEquals("otherUser",newFc.getUgi().getUserName());
204   }
205 
getGroups()206   static List<String> getGroups() throws IOException {
207     List<String> a = new ArrayList<String>();
208     String s = Shell.execCommand(Shell.getGroupsCommand());
209     for(StringTokenizer t = new StringTokenizer(s); t.hasMoreTokens(); ) {
210       a.add(t.nextToken());
211     }
212     return a;
213   }
214 
215 
doFilePermissionCheck(FsPermission expectedPerm, FsPermission actualPerm)216   void doFilePermissionCheck(FsPermission expectedPerm, FsPermission actualPerm) {
217   Assert.assertEquals(expectedPerm.applyUMask(getFileMask()), actualPerm);
218   }
219 
220 
221   /*
222    * Override the method below if the file system being tested masks our
223    * certain bits for file masks.
224    */
225   static final FsPermission FILE_MASK_ZERO = new FsPermission((short) 0);
getFileMask()226   FsPermission getFileMask() {
227     return FILE_MASK_ZERO;
228   }
229 }
230