|
1 /* |
|
2 * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. |
|
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
|
4 * |
|
5 * This code is free software; you can redistribute it and/or modify it |
|
6 * under the terms of the GNU General Public License version 2 only, as |
|
7 * published by the Free Software Foundation. |
|
8 * |
|
9 * This code is distributed in the hope that it will be useful, but WITHOUT |
|
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
|
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
|
12 * version 2 for more details (a copy is included in the LICENSE file that |
|
13 * accompanied this code). |
|
14 * |
|
15 * You should have received a copy of the GNU General Public License version |
|
16 * 2 along with this work; if not, write to the Free Software Foundation, |
|
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
|
18 * |
|
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
|
20 * or visit www.oracle.com if you need additional information or have any |
|
21 * questions. |
|
22 */ |
|
23 |
|
24 /* @test |
|
25 * @bug 8017212 |
|
26 * @summary Examine methods in File.java that access the file system do the |
|
27 * right permission check when a security manager exists. |
|
28 * @author Dan Xu |
|
29 */ |
|
30 |
|
31 import java.io.File; |
|
32 import java.io.FilenameFilter; |
|
33 import java.io.FileFilter; |
|
34 import java.io.IOException; |
|
35 import java.security.Permission; |
|
36 import java.util.ArrayList; |
|
37 import java.util.EnumMap; |
|
38 import java.util.EnumSet; |
|
39 import java.util.HashSet; |
|
40 import java.util.List; |
|
41 import java.util.Map; |
|
42 import java.util.Set; |
|
43 |
|
44 public class CheckPermission { |
|
45 |
|
46 private static final String CHECK_PERMISSION_TEST = "CheckPermissionTest"; |
|
47 |
|
48 public enum FileOperation { |
|
49 READ, WRITE, DELETE, EXEC |
|
50 } |
|
51 |
|
52 static class Checks { |
|
53 private List<Permission> permissionsChecked = new ArrayList<>(); |
|
54 private Set<String> propertiesChecked = new HashSet<>(); |
|
55 |
|
56 private Map<FileOperation, List<String>> fileOperationChecked = |
|
57 new EnumMap<>(FileOperation.class); |
|
58 |
|
59 List<Permission> permissionsChecked() { |
|
60 return permissionsChecked; |
|
61 } |
|
62 |
|
63 Set<String> propertiesChecked() { |
|
64 return propertiesChecked; |
|
65 } |
|
66 |
|
67 List<String> fileOperationChecked(FileOperation op) { |
|
68 return fileOperationChecked.get(op); |
|
69 } |
|
70 |
|
71 void addFileOperation(FileOperation op, String file) { |
|
72 List<String> opList = fileOperationChecked.get(op); |
|
73 if (opList == null) { |
|
74 opList = new ArrayList<>(); |
|
75 fileOperationChecked.put(op, opList); |
|
76 } |
|
77 opList.add(file); |
|
78 } |
|
79 } |
|
80 |
|
81 static ThreadLocal<Checks> myChecks = new ThreadLocal<>(); |
|
82 |
|
83 static void prepare() { |
|
84 myChecks.set(new Checks()); |
|
85 } |
|
86 |
|
87 static class LoggingSecurityManager extends SecurityManager { |
|
88 static void install() { |
|
89 System.setSecurityManager(new LoggingSecurityManager()); |
|
90 } |
|
91 |
|
92 private void checkFileOperation(FileOperation op, String file) { |
|
93 Checks checks = myChecks.get(); |
|
94 if (checks != null) |
|
95 checks.addFileOperation(op, file); |
|
96 } |
|
97 |
|
98 @Override |
|
99 public void checkRead(String file) { |
|
100 checkFileOperation(FileOperation.READ, file); |
|
101 } |
|
102 |
|
103 @Override |
|
104 public void checkWrite(String file) { |
|
105 checkFileOperation(FileOperation.WRITE, file); |
|
106 } |
|
107 |
|
108 @Override |
|
109 public void checkDelete(String file) { |
|
110 checkFileOperation(FileOperation.DELETE, file); |
|
111 } |
|
112 |
|
113 @Override |
|
114 public void checkExec(String file) { |
|
115 checkFileOperation(FileOperation.EXEC, file); |
|
116 } |
|
117 |
|
118 @Override |
|
119 public void checkPermission(Permission perm) { |
|
120 Checks checks = myChecks.get(); |
|
121 if (checks != null) |
|
122 checks.permissionsChecked().add(perm); |
|
123 } |
|
124 |
|
125 @Override |
|
126 public void checkPropertyAccess(String key) { |
|
127 Checks checks = myChecks.get(); |
|
128 if (checks != null) |
|
129 checks.propertiesChecked().add(key); |
|
130 } |
|
131 } |
|
132 |
|
133 static void assertCheckPermission(Class<? extends Permission> type, |
|
134 String name) |
|
135 { |
|
136 for (Permission perm : myChecks.get().permissionsChecked()) { |
|
137 if (type.isInstance(perm) && perm.getName().equals(name)) |
|
138 return; |
|
139 } |
|
140 throw new RuntimeException(type.getName() + "(\"" + name |
|
141 + "\") not checked"); |
|
142 } |
|
143 |
|
144 static void assertCheckPropertyAccess(String key) { |
|
145 if (!myChecks.get().propertiesChecked().contains(key)) |
|
146 throw new RuntimeException("Property " + key + " not checked"); |
|
147 } |
|
148 |
|
149 static void assertChecked(File file, List<String> list) { |
|
150 if (list != null && !list.isEmpty()) { |
|
151 for (String path : list) { |
|
152 if (path.equals(file.getPath())) |
|
153 return; |
|
154 } |
|
155 } |
|
156 throw new RuntimeException("Access not checked"); |
|
157 } |
|
158 |
|
159 static void assertNotChecked(File file, List<String> list) { |
|
160 if (list != null && !list.isEmpty()) { |
|
161 for (String path : list) { |
|
162 if (path.equals(file.getPath())) |
|
163 throw new RuntimeException("Access checked"); |
|
164 } |
|
165 } |
|
166 } |
|
167 |
|
168 static void assertCheckOperation(File file, Set<FileOperation> ops) { |
|
169 for (FileOperation op : ops) |
|
170 assertChecked(file, myChecks.get().fileOperationChecked(op)); |
|
171 } |
|
172 |
|
173 static void assertNotCheckOperation(File file, Set<FileOperation> ops) { |
|
174 for (FileOperation op : ops) |
|
175 assertNotChecked(file, myChecks.get().fileOperationChecked(op)); |
|
176 } |
|
177 |
|
178 static void assertOnlyCheckOperation(File file, |
|
179 EnumSet<FileOperation> ops) |
|
180 { |
|
181 assertCheckOperation(file, ops); |
|
182 assertNotCheckOperation(file, EnumSet.complementOf(ops)); |
|
183 } |
|
184 |
|
185 static File testFile, another; |
|
186 |
|
187 static void setup() { |
|
188 testFile = new File(CHECK_PERMISSION_TEST + System.currentTimeMillis()); |
|
189 if (testFile.exists()) { |
|
190 testFile.delete(); |
|
191 } |
|
192 |
|
193 another = new File(CHECK_PERMISSION_TEST + "Another" |
|
194 + System.currentTimeMillis()); |
|
195 if (another.exists()) { |
|
196 another.delete(); |
|
197 } |
|
198 |
|
199 LoggingSecurityManager.install(); |
|
200 } |
|
201 |
|
202 public static void main(String[] args) throws IOException { |
|
203 setup(); |
|
204 |
|
205 prepare(); |
|
206 testFile.canRead(); |
|
207 assertOnlyCheckOperation(testFile, EnumSet.of(FileOperation.READ)); |
|
208 |
|
209 prepare(); |
|
210 testFile.canWrite(); |
|
211 assertOnlyCheckOperation(testFile, EnumSet.of(FileOperation.WRITE)); |
|
212 |
|
213 prepare(); |
|
214 testFile.exists(); |
|
215 assertOnlyCheckOperation(testFile, EnumSet.of(FileOperation.READ)); |
|
216 |
|
217 prepare(); |
|
218 testFile.isDirectory(); |
|
219 assertOnlyCheckOperation(testFile, EnumSet.of(FileOperation.READ)); |
|
220 |
|
221 prepare(); |
|
222 testFile.isFile(); |
|
223 assertOnlyCheckOperation(testFile, EnumSet.of(FileOperation.READ)); |
|
224 |
|
225 prepare(); |
|
226 testFile.isHidden(); |
|
227 assertOnlyCheckOperation(testFile, EnumSet.of(FileOperation.READ)); |
|
228 |
|
229 prepare(); |
|
230 testFile.lastModified(); |
|
231 assertOnlyCheckOperation(testFile, EnumSet.of(FileOperation.READ)); |
|
232 |
|
233 prepare(); |
|
234 testFile.length(); |
|
235 assertOnlyCheckOperation(testFile, EnumSet.of(FileOperation.READ)); |
|
236 |
|
237 prepare(); |
|
238 testFile.createNewFile(); |
|
239 assertOnlyCheckOperation(testFile, EnumSet.of(FileOperation.WRITE)); |
|
240 |
|
241 prepare(); |
|
242 testFile.list(); |
|
243 assertOnlyCheckOperation(testFile, EnumSet.of(FileOperation.READ)); |
|
244 |
|
245 prepare(); |
|
246 testFile.list(new FilenameFilter() { |
|
247 @Override |
|
248 public boolean accept(File dir, String name) { |
|
249 return false; |
|
250 } |
|
251 }); |
|
252 assertOnlyCheckOperation(testFile, EnumSet.of(FileOperation.READ)); |
|
253 |
|
254 prepare(); |
|
255 testFile.listFiles(); |
|
256 assertOnlyCheckOperation(testFile, EnumSet.of(FileOperation.READ)); |
|
257 |
|
258 prepare(); |
|
259 testFile.listFiles(new FilenameFilter() { |
|
260 @Override |
|
261 public boolean accept(File dir, String name) { |
|
262 return false; |
|
263 } |
|
264 }); |
|
265 assertOnlyCheckOperation(testFile, EnumSet.of(FileOperation.READ)); |
|
266 |
|
267 prepare(); |
|
268 testFile.listFiles(new FileFilter() { |
|
269 @Override |
|
270 public boolean accept(File file) { |
|
271 return false; |
|
272 } |
|
273 }); |
|
274 assertOnlyCheckOperation(testFile, EnumSet.of(FileOperation.READ)); |
|
275 |
|
276 prepare(); |
|
277 testFile.mkdir(); |
|
278 assertOnlyCheckOperation(testFile, EnumSet.of(FileOperation.WRITE)); |
|
279 |
|
280 if (testFile.exists()) { |
|
281 prepare(); |
|
282 testFile.mkdirs(); |
|
283 assertOnlyCheckOperation(testFile, EnumSet.of(FileOperation.READ)); |
|
284 } |
|
285 |
|
286 if (!another.exists()) { |
|
287 prepare(); |
|
288 another.mkdirs(); |
|
289 assertOnlyCheckOperation(another, |
|
290 EnumSet.of(FileOperation.READ, FileOperation.WRITE)); |
|
291 } |
|
292 |
|
293 prepare(); |
|
294 another.delete(); |
|
295 assertOnlyCheckOperation(another, EnumSet.of(FileOperation.DELETE)); |
|
296 |
|
297 prepare(); |
|
298 boolean renRst = testFile.renameTo(another); |
|
299 assertOnlyCheckOperation(testFile, EnumSet.of(FileOperation.WRITE)); |
|
300 assertOnlyCheckOperation(another, EnumSet.of(FileOperation.WRITE)); |
|
301 |
|
302 if (renRst) { |
|
303 if (testFile.exists()) |
|
304 throw new RuntimeException(testFile + " is already renamed to " |
|
305 + another); |
|
306 testFile = another; |
|
307 } |
|
308 |
|
309 prepare(); |
|
310 testFile.setLastModified(0); |
|
311 assertOnlyCheckOperation(testFile, EnumSet.of(FileOperation.WRITE)); |
|
312 |
|
313 prepare(); |
|
314 testFile.setReadOnly(); |
|
315 assertOnlyCheckOperation(testFile, EnumSet.of(FileOperation.WRITE)); |
|
316 |
|
317 prepare(); |
|
318 testFile.setWritable(true, true); |
|
319 assertOnlyCheckOperation(testFile, EnumSet.of(FileOperation.WRITE)); |
|
320 |
|
321 prepare(); |
|
322 testFile.setWritable(true); |
|
323 assertOnlyCheckOperation(testFile, EnumSet.of(FileOperation.WRITE)); |
|
324 |
|
325 prepare(); |
|
326 testFile.setReadable(true, true); |
|
327 assertOnlyCheckOperation(testFile, EnumSet.of(FileOperation.WRITE)); |
|
328 |
|
329 prepare(); |
|
330 testFile.setReadable(true); |
|
331 assertOnlyCheckOperation(testFile, EnumSet.of(FileOperation.WRITE)); |
|
332 |
|
333 prepare(); |
|
334 testFile.setExecutable(true, true); |
|
335 assertOnlyCheckOperation(testFile, EnumSet.of(FileOperation.WRITE)); |
|
336 |
|
337 prepare(); |
|
338 testFile.setExecutable(true); |
|
339 assertOnlyCheckOperation(testFile, EnumSet.of(FileOperation.WRITE)); |
|
340 |
|
341 prepare(); |
|
342 testFile.canExecute(); |
|
343 assertOnlyCheckOperation(testFile, EnumSet.of(FileOperation.EXEC)); |
|
344 |
|
345 prepare(); |
|
346 testFile.getTotalSpace(); |
|
347 assertOnlyCheckOperation(testFile, EnumSet.of(FileOperation.READ)); |
|
348 assertCheckPermission(RuntimePermission.class, |
|
349 "getFileSystemAttributes"); |
|
350 |
|
351 prepare(); |
|
352 testFile.getFreeSpace(); |
|
353 assertOnlyCheckOperation(testFile, EnumSet.of(FileOperation.READ)); |
|
354 assertCheckPermission(RuntimePermission.class, |
|
355 "getFileSystemAttributes"); |
|
356 |
|
357 prepare(); |
|
358 testFile.getUsableSpace(); |
|
359 assertOnlyCheckOperation(testFile, EnumSet.of(FileOperation.READ)); |
|
360 assertCheckPermission(RuntimePermission.class, |
|
361 "getFileSystemAttributes"); |
|
362 |
|
363 prepare(); |
|
364 File tmpFile = File.createTempFile(CHECK_PERMISSION_TEST, null); |
|
365 assertOnlyCheckOperation(tmpFile, EnumSet.of(FileOperation.WRITE)); |
|
366 tmpFile.delete(); |
|
367 assertCheckOperation(tmpFile, EnumSet.of(FileOperation.DELETE)); |
|
368 |
|
369 prepare(); |
|
370 tmpFile = File.createTempFile(CHECK_PERMISSION_TEST, null, null); |
|
371 assertOnlyCheckOperation(tmpFile, EnumSet.of(FileOperation.WRITE)); |
|
372 tmpFile.delete(); |
|
373 assertCheckOperation(tmpFile, EnumSet.of(FileOperation.DELETE)); |
|
374 |
|
375 prepare(); |
|
376 testFile.deleteOnExit(); |
|
377 assertOnlyCheckOperation(testFile, EnumSet.of(FileOperation.DELETE)); |
|
378 } |
|
379 } |