blob: 5ce3ca50cbd03c9c9a1b69301139b009cce4bee1 [file] [log] [blame]
Karl Pauls36407322008-03-07 00:37:30 +00001/*
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,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19package org.apache.felix.framework.security.util;
20
21import java.io.File;
22import java.io.FilePermission;
23import java.lang.ref.ReferenceQueue;
24import java.lang.ref.SoftReference;
25import java.lang.ref.WeakReference;
26import java.security.AllPermission;
27import java.security.Permission;
28import java.security.PermissionCollection;
Karl Paulse0e4b292008-12-16 15:50:06 +000029import java.security.*;
Karl Pauls36407322008-03-07 00:37:30 +000030import java.util.Enumeration;
31import java.util.HashMap;
32import java.util.HashSet;
33import java.util.Iterator;
34import java.util.Map;
35
36import org.apache.felix.framework.util.SecureAction;
37import org.osgi.framework.AdminPermission;
38import org.osgi.framework.Bundle;
39import org.osgi.framework.BundleContext;
40import org.osgi.framework.InvalidSyntaxException;
41import org.osgi.framework.ServiceReference;
42import org.osgi.service.packageadmin.ExportedPackage;
43import org.osgi.service.packageadmin.PackageAdmin;
44import org.osgi.service.permissionadmin.PermissionInfo;
45
46/**
47 * A permission cache that uses permisssion infos as keys. Permission are created
48 * from the parent classloader or any exported package.
49 */
50// TODO: maybe use bundle events instead of soft/weak references
51public final class Permissions
52{
53 private static final ClassLoader m_classLoader =
54 Permissions.class.getClassLoader();
55
56 private static final Map m_permissionCache = new HashMap();
57 private static final Map m_permissions = new HashMap();
58 private static final ReferenceQueue m_permissionsQueue =
59 new ReferenceQueue();
60
61 private static final ThreadLocal m_stack = new ThreadLocal();
62
63 private final Map m_cache;
64 private final ReferenceQueue m_queue;
65 private final BundleContext m_context;
66 private final PermissionInfo[] m_permissionInfos;
67 private final boolean m_allPermission;
68 private final SecureAction m_action;
69
70 public static final AllPermission ALL_PERMISSION = new AllPermission();
71
72 private static final PermissionInfo[] IMPLICIT =
73 new PermissionInfo[] { new PermissionInfo(FilePermission.class
74 .getName(), "-", "read,write,delete") };
75
76 Permissions(PermissionInfo[] permissionInfos, BundleContext context,
77 SecureAction action)
78 {
79 m_context = context;
80 m_permissionInfos = permissionInfos;
81 m_cache = new HashMap();
82 m_queue = new ReferenceQueue();
83 m_action = action;
84 for (int i = 0; i < m_permissionInfos.length; i++)
85 {
86 if (m_permissionInfos[i].getType().equals(
87 AllPermission.class.getName()))
88 {
89 m_allPermission = true;
90 return;
91 }
92 }
93 m_allPermission = false;
94 }
95
96 public Permissions(BundleContext context, SecureAction action)
97 {
98 m_context = context;
99 m_permissionInfos = null;
100 m_cache = null;
101 m_queue = null;
102 m_allPermission = true;
103 m_action = action;
104 }
105
106 public PermissionInfo[] getImplicit(Bundle bundle)
107 {
108 return new PermissionInfo[] {
109 IMPLICIT[0],
110 new PermissionInfo(AdminPermission.class.getName(), "(id="
111 + bundle.getBundleId() + ")", AdminPermission.METADATA) };
112 }
113
114 public Permissions getPermissions(PermissionInfo[] permissionInfos)
115 {
116 cleanUp(m_permissionsQueue, m_permissions);
117
118 Permissions result = null;
119 synchronized (m_permissions)
120 {
121 result = (Permissions) m_permissions.get(permissionInfos);
122 }
123 if (result == null)
124 {
125 result = new Permissions(permissionInfos, m_context, m_action);
126 synchronized (m_permissions)
127 {
128 m_permissions.put(
129 new Entry(permissionInfos, m_permissionsQueue), result);
130 }
131 }
132 return result;
133 }
134
135 private static final class Entry extends WeakReference
136 {
137 private final int m_hashCode;
138
139 Entry(Object entry, ReferenceQueue queue)
140 {
141 super(entry, queue);
142 m_hashCode = entry.hashCode();
143 }
144
145 Entry(Object entry)
146 {
147 super(entry);
148 m_hashCode = entry.hashCode();
149 }
150
151 public Object get()
152 {
153 return super.get();
154 }
155
156 public int hashCode()
157 {
158 return m_hashCode;
159 }
160
161 public boolean equals(Object o)
162 {
163 if (o == null)
164 {
165 return false;
166 }
167
168 if (o == this)
169 {
170 return true;
171 }
172
173 Object entry = super.get();
174
175 if (entry == null)
176 {
177 return false;
178 }
179
Karl Paulsd3b03742009-01-28 00:27:49 +0000180 if (o instanceof Entry)
181 {
182 return entry.equals(((Entry)o).get());
183 }
184 else
185 {
186 return false;
187 }
Karl Pauls36407322008-03-07 00:37:30 +0000188 }
189 }
190
191 private static final class DefaultPermissionCollection extends
192 PermissionCollection
193 {
194 private final Map m_perms = new HashMap();
195
196 public void add(Permission perm)
197 {
198 synchronized (m_perms)
199 {
200 m_perms.put(perm, perm);
201 }
202 }
203
204 public Enumeration elements()
205 {
206 throw new IllegalStateException("Not implemented");
207 }
208
209 public boolean implies(Permission perm)
210 {
211 Map perms = null;
212
213 synchronized (m_perms)
214 {
215 perms = m_perms;
216 }
217
218 Permission permission = (Permission) perms.get(perm);
219
220 if ((permission != null) && permission.implies(perm))
221 {
222 return true;
223 }
224
225 for (Iterator iter = perms.values().iterator(); iter.hasNext();)
226 {
227 Permission current = (Permission) iter.next();
228 if ((current != null) && (current != permission)
229 && current.implies(perm))
230 {
231 return true;
232 }
233 }
234 return false;
235 }
236 }
237
238 private void cleanUp(ReferenceQueue queue, Map cache)
239 {
240 for (Entry entry = (Entry) queue.poll(); entry != null; entry =
241 (Entry) queue.poll())
242 {
243 synchronized (cache)
244 {
245 cache.remove(entry);
246 }
247 }
248 }
249
250 /**
251 * @param target the permission to be implied
252 * @param bundle if not null then allow implicit permissions like file
253 * access to local data area
254 * @return true if the permission is implied by this permissions object.
255 */
256 public boolean implies(Permission target, Bundle bundle)
257 {
258 if (m_allPermission)
259 {
260 return true;
261 }
262
263 Class targetClass = target.getClass();
264
265 cleanUp(m_queue, m_cache);
266
267 if ((bundle != null) && targetClass == FilePermission.class)
268 {
269 for (int i = 0; i < m_permissionInfos.length; i++)
270 {
271 if (m_permissionInfos[i].getType().equals(
272 FilePermission.class.getName()))
273 {
274 String postfix = "";
275 String name = m_permissionInfos[i].getName();
Karl Paulsdc1e7f82009-11-25 20:38:36 +0000276 if (!"<<ALL FILES>>".equals(name))
Karl Pauls36407322008-03-07 00:37:30 +0000277 {
Karl Paulsdc1e7f82009-11-25 20:38:36 +0000278 if (name.endsWith("*") || name.endsWith("-"))
Karl Pauls36407322008-03-07 00:37:30 +0000279 {
Karl Paulsdc1e7f82009-11-25 20:38:36 +0000280 postfix = name.substring(name.length() - 1);
281 name = name.substring(0, name.length() - 1);
Karl Pauls36407322008-03-07 00:37:30 +0000282 }
Karl Paulsdc1e7f82009-11-25 20:38:36 +0000283 if (!(new File(name)).isAbsolute())
Karl Pauls36407322008-03-07 00:37:30 +0000284 {
Karl Paulsdc1e7f82009-11-25 20:38:36 +0000285 BundleContext context = bundle.getBundleContext();
286 if (context == null)
287 {
288 break;
289 }
290 name =
291 m_action.getAbsolutePath(new File(context.getDataFile(""), name));
Karl Pauls36407322008-03-07 00:37:30 +0000292 }
Karl Paulsdc1e7f82009-11-25 20:38:36 +0000293 if (postfix.length() > 0)
Karl Pauls36407322008-03-07 00:37:30 +0000294 {
Karl Paulsdc1e7f82009-11-25 20:38:36 +0000295 if ((name.length() > 0) && !name.endsWith("/"))
296 {
297 name += "/" + postfix;
298 }
299 else
300 {
301 name += postfix;
302 }
Karl Pauls36407322008-03-07 00:37:30 +0000303 }
304 }
305 return createPermission(
306 new PermissionInfo(FilePermission.class.getName(),
307 name, m_permissionInfos[i].getActions()),
308 targetClass).implies(target);
309 }
310 }
311 return false;
312 }
313
314 Object current = m_stack.get();
315
316 if (current == null)
317 {
318 m_stack.set(targetClass);
319 }
320 else
321 {
322 if (current instanceof HashSet)
323 {
324 if (((HashSet) current).contains(targetClass))
325 {
326 return false;
327 }
328 ((HashSet) current).add(targetClass);
329 }
330 else
331 {
332 if (current == targetClass)
333 {
334 return false;
335 }
336 HashSet frame = new HashSet();
337 frame.add(current);
338 frame.add(targetClass);
339 m_stack.set(frame);
340 current = frame;
341 }
342 }
343
344 try
345 {
346 SoftReference collectionEntry = null;
347
348 PermissionCollection collection = null;
349
350 synchronized (m_cache)
351 {
352 collectionEntry = (SoftReference) m_cache.get(targetClass);
353 }
354
355 if (collectionEntry != null)
356 {
357 collection = (PermissionCollection) collectionEntry.get();
358 }
359
360 if (collection == null)
361 {
362 collection = target.newPermissionCollection();
363
364 if (collection == null)
365 {
366 collection = new DefaultPermissionCollection();
367 }
368
369 for (int i = 0; i < m_permissionInfos.length; i++)
370 {
371 PermissionInfo permissionInfo = m_permissionInfos[i];
372 String infoType = permissionInfo.getType();
373 String permissionType = targetClass.getName();
374
375 if (infoType.equals(permissionType))
376 {
377 Permission permission =
378 createPermission(permissionInfo, targetClass);
379
380 if (permission != null)
381 {
382 collection.add(permission);
383 }
384 }
385 }
386
387 synchronized (m_cache)
388 {
389 m_cache.put(new Entry(target.getClass(), m_queue),
390 new SoftReference(collection));
391 }
392 }
393
394 return collection.implies(target);
395 }
396 finally
397 {
398 if (current == null)
399 {
400 m_stack.set(null);
401 }
402 else
403 {
404 ((HashSet) current).remove(targetClass);
405 if (((HashSet) current).isEmpty())
406 {
407 m_stack.set(null);
408 }
409 }
410 }
411 }
412
413 private Permission addToCache(String encoded, Permission permission)
414 {
415 if (permission == null)
416 {
417 return null;
418 }
419
420 synchronized (m_permissionCache)
421 {
422 Map inner = null;
423
424 SoftReference ref = (SoftReference) m_permissionCache.get(encoded);
425 if (ref != null)
426 {
427 inner = (Map) ref.get();
428 }
429 if (inner == null)
430 {
431 inner = new HashMap();
432 m_permissionCache.put(encoded,
433 new SoftReference(inner, m_queue));
434 }
435
436 inner.put(new Entry(permission.getClass()), new Entry(permission));
437 }
438
439 return permission;
440 }
441
442 private Permission getFromCache(String encoded, Class target)
443 {
444 synchronized (m_permissionCache)
445 {
446 SoftReference ref = (SoftReference) m_permissionCache.get(encoded);
447 if (ref != null)
448 {
449 Map inner = (Map) ref.get();
450 if (inner != null)
451 {
452 Entry entry = (Entry) inner.get(target);
453 if (entry != null)
454 {
455 Permission result = (Permission) entry.get();
456 if (result != null)
457 {
458 return result;
459 }
460 inner.remove(entry);
461 }
462 if (inner.isEmpty())
463 {
464 m_permissionCache.remove(encoded);
465 }
466 }
467 else
468 {
469 m_permissionCache.remove(encoded);
470 }
471 }
472
473 }
474
475 return null;
476 }
477
Karl Paulse0e4b292008-12-16 15:50:06 +0000478 private Permission createPermission(final PermissionInfo permissionInfo,
479 final Class target)
Karl Pauls36407322008-03-07 00:37:30 +0000480 {
Karl Paulse0e4b292008-12-16 15:50:06 +0000481 return (Permission) AccessController.doPrivileged(new PrivilegedAction() {
482 public Object run()
483 {
Karl Pauls36407322008-03-07 00:37:30 +0000484 Permission cached = getFromCache(permissionInfo.getEncoded(), target);
485
486 if (cached != null)
487 {
488 return cached;
489 }
490
491 try
492 {
493 if (m_classLoader.loadClass(target.getName()) == target)
494 {
495 return addToCache(permissionInfo.getEncoded(),
496 createPermission(permissionInfo.getName(), permissionInfo
497 .getActions(), target));
498 }
499 }
500 catch (ClassNotFoundException e1)
501 {
502 }
503
504 ServiceReference[] refs = null;
505 try
506 {
507 refs =
508 m_context.getServiceReferences(PackageAdmin.class.getName(),
509 null);
510 }
511 catch (InvalidSyntaxException e)
512 {
513 }
514 if (refs != null)
515 {
516 for (int i = 0; i < refs.length; i++)
517 {
518 PackageAdmin admin =
519 (PackageAdmin) m_context.getService(refs[i]);
520
521 if (admin != null)
522 {
523 Permission result = null;
524 Bundle bundle = admin.getBundle(target);
525 if (bundle != null)
526 {
527 ExportedPackage[] exports =
528 admin.getExportedPackages(bundle);
529 if (exports != null)
530 {
531 String name = target.getName();
532 name = name.substring(0, name.lastIndexOf('.'));
533
534 for (int j = 0; j < exports.length; j++)
535 {
536 if (exports[j].getName().equals(name))
537 {
538 result =
539 createPermission(permissionInfo
540 .getName(), permissionInfo
541 .getActions(), target);
542 break;
543 }
544 }
545 }
546 }
547
548 m_context.ungetService(refs[i]);
549
550 return addToCache(permissionInfo.getEncoded(), result);
551 }
552 }
553 }
554
555 return null;
Karl Paulse0e4b292008-12-16 15:50:06 +0000556 }});
Karl Pauls36407322008-03-07 00:37:30 +0000557 }
558
559 private Permission createPermission(String name, String action, Class target)
560 {
561 try
562 {
563 return (Permission) m_action.getConstructor(target,
564 new Class[] { String.class, String.class }).newInstance(
565 new Object[] { name, action });
566 }
567 catch (Exception ex)
568 {
569 ex.printStackTrace();
570 }
571
572 return null;
573 }
574}