1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.vfs2.impl;
18
19 import java.io.IOException;
20 import java.net.URL;
21 import java.security.CodeSource;
22 import java.security.Permission;
23 import java.security.PermissionCollection;
24 import java.security.Permissions;
25 import java.security.SecureClassLoader;
26 import java.security.cert.Certificate;
27 import java.util.ArrayList;
28 import java.util.Collections;
29 import java.util.Enumeration;
30 import java.util.List;
31 import java.util.jar.Attributes;
32 import java.util.jar.Attributes.Name;
33
34 import org.apache.commons.vfs2.FileObject;
35 import org.apache.commons.vfs2.FileSystemException;
36 import org.apache.commons.vfs2.FileSystemManager;
37 import org.apache.commons.vfs2.NameScope;
38 import org.apache.commons.vfs2.util.FileObjectUtils;
39
40
41
42
43
44
45
46
47
48
49
50
51
52 public class VFSClassLoader extends SecureClassLoader {
53 private final ArrayList<FileObject> resources = new ArrayList<>();
54
55
56
57
58
59
60
61
62 public VFSClassLoader(final FileObject file, final FileSystemManager manager) throws FileSystemException {
63 this(new FileObject[] { file }, manager, null);
64 }
65
66
67
68
69
70
71
72
73
74 public VFSClassLoader(final FileObject file, final FileSystemManager manager, final ClassLoader parent)
75 throws FileSystemException {
76 this(new FileObject[] { file }, manager, parent);
77 }
78
79
80
81
82
83
84
85
86 public VFSClassLoader(final FileObject[] files, final FileSystemManager manager) throws FileSystemException {
87 this(files, manager, null);
88 }
89
90
91
92
93
94
95
96
97
98
99 public VFSClassLoader(final FileObject[] files, final FileSystemManager manager, final ClassLoader parent)
100 throws FileSystemException {
101 super(parent);
102 addFileObjects(manager, files);
103 }
104
105
106
107
108
109
110
111 public FileObject[] getFileObjects() {
112 return resources.toArray(FileObject.EMPTY_ARRAY);
113 }
114
115
116
117
118
119
120
121
122 private void addFileObjects(final FileSystemManager manager, final FileObject[] files) throws FileSystemException {
123 for (FileObject file : files) {
124 if (!FileObjectUtils.exists(file)) {
125
126 continue;
127 }
128
129
130 if (manager.canCreateFileSystem(file)) {
131
132 file = manager.createFileSystem(file);
133 }
134
135 resources.add(file);
136 }
137 }
138
139
140
141
142
143
144 @Override
145 protected Class<?> findClass(final String name) throws ClassNotFoundException {
146 try {
147 final String path = name.replace('.', '/').concat(".class");
148 final Resource res = loadResource(path);
149 if (res == null) {
150 throw new ClassNotFoundException(name);
151 }
152 return defineClass(name, res);
153 } catch (final IOException ioe) {
154 throw new ClassNotFoundException(name, ioe);
155 }
156 }
157
158
159
160
161 private Class<?> defineClass(final String name, final Resource res) throws IOException {
162 final URL url = res.getCodeSourceURL();
163 final String pkgName = res.getPackageName();
164 if (pkgName != null) {
165 final Package pkg = getPackage(pkgName);
166 if (pkg != null) {
167 if (pkg.isSealed()) {
168 if (!pkg.isSealed(url)) {
169 throw new FileSystemException("vfs.impl/pkg-sealed-other-url", pkgName);
170 }
171 } else if (isSealed(res)) {
172 throw new FileSystemException("vfs.impl/pkg-sealing-unsealed", pkgName);
173 }
174 } else {
175 definePackage(pkgName, res);
176 }
177 }
178
179 final byte[] bytes = res.getBytes();
180 final Certificate[] certs = res.getFileObject().getContent().getCertificates();
181 final CodeSource cs = new CodeSource(url, certs);
182 return defineClass(name, bytes, 0, bytes.length, cs);
183 }
184
185
186
187
188 private boolean isSealed(final Resource res) throws FileSystemException {
189 final String sealed = res.getPackageAttribute(Attributes.Name.SEALED);
190 return "true".equalsIgnoreCase(sealed);
191 }
192
193
194
195
196 private Package definePackage(final String name, final Resource res) throws FileSystemException {
197
198 final String specTitle = res.getPackageAttribute(Name.SPECIFICATION_TITLE);
199 final String specVendor = res.getPackageAttribute(Attributes.Name.SPECIFICATION_VENDOR);
200 final String specVersion = res.getPackageAttribute(Name.SPECIFICATION_VERSION);
201 final String implTitle = res.getPackageAttribute(Name.IMPLEMENTATION_TITLE);
202 final String implVendor = res.getPackageAttribute(Name.IMPLEMENTATION_VENDOR);
203 final String implVersion = res.getPackageAttribute(Name.IMPLEMENTATION_VERSION);
204
205 final URL sealBase;
206 if (isSealed(res)) {
207 sealBase = res.getCodeSourceURL();
208 } else {
209 sealBase = null;
210 }
211
212 return definePackage(name, specTitle, specVersion, specVendor, implTitle, implVersion, implVendor, sealBase);
213 }
214
215
216
217
218
219
220
221 @Override
222 protected PermissionCollection getPermissions(final CodeSource cs) {
223 try {
224 final String url = cs.getLocation().toString();
225 final FileObject file = lookupFileObject(url);
226 if (file == null) {
227 return super.getPermissions(cs);
228 }
229
230 final FileObject parentLayer = file.getFileSystem().getParentLayer();
231 if (parentLayer == null) {
232 return super.getPermissions(cs);
233 }
234
235 final Permissions combi = new Permissions();
236 PermissionCollection permCollect = super.getPermissions(cs);
237 copyPermissions(permCollect, combi);
238
239 for (FileObject parent = parentLayer; parent != null; parent = parent.getFileSystem().getParentLayer()) {
240 final CodeSource parentcs = new CodeSource(parent.getURL(), parent.getContent().getCertificates());
241 permCollect = super.getPermissions(parentcs);
242 copyPermissions(permCollect, combi);
243 }
244
245 return combi;
246 } catch (final FileSystemException fse) {
247 throw new SecurityException(fse.getMessage());
248 }
249 }
250
251
252
253
254
255
256
257 protected void copyPermissions(final PermissionCollection src, final PermissionCollection dest) {
258 for (final Enumeration<Permission> elem = src.elements(); elem.hasMoreElements();) {
259 final Permission permission = elem.nextElement();
260 dest.add(permission);
261 }
262 }
263
264
265
266
267 private FileObject lookupFileObject(final String name) {
268 for (final FileObject object : resources) {
269 if (name.equals(object.getName().getURI())) {
270 return object;
271 }
272 }
273 return null;
274 }
275
276
277
278
279
280
281
282 @Override
283 protected URL findResource(final String name) {
284 try {
285 final Resource res = loadResource(name);
286 if (res != null) {
287 return res.getURL();
288 }
289 return null;
290 } catch (final Exception ignored) {
291 return null;
292 }
293 }
294
295
296
297
298
299
300
301
302
303
304 @Override
305 protected Enumeration<URL> findResources(final String name) throws IOException {
306 final List<URL> result = new ArrayList<>(2);
307
308 for (final FileObject baseFile : resources) {
309 try (final FileObject file = baseFile.resolveFile(name, NameScope.DESCENDENT_OR_SELF)) {
310 if (FileObjectUtils.exists(file)) {
311 result.add(new Resource(name, baseFile, file).getURL());
312 }
313 }
314 }
315
316 return Collections.enumeration(result);
317 }
318
319
320
321
322
323
324
325
326 private Resource loadResource(final String name) throws FileSystemException {
327 for (final FileObject baseFile : resources) {
328 try (final FileObject file = baseFile.resolveFile(name, NameScope.DESCENDENT_OR_SELF)) {
329 if (FileObjectUtils.exists(file)) {
330 return new Resource(name, baseFile, file);
331 }
332 }
333 }
334 return null;
335 }
336 }