Richard S. Hall | 930fecc | 2005-08-16 18:33:34 +0000 | [diff] [blame] | 1 | /* |
| 2 | * $Header: /cvshome/build/org.osgi.framework/src/org/osgi/framework/AdminPermission.java,v 1.12 2005/05/13 20:32:54 hargrave Exp $ |
| 3 | * |
| 4 | * Copyright (c) OSGi Alliance (2000, 2005). All Rights Reserved. |
| 5 | * |
| 6 | * This program and the accompanying materials are made available under the |
| 7 | * terms of the Eclipse Public License v1.0 which accompanies this |
| 8 | * distribution, and is available at http://www.eclipse.org/legal/epl-v10.html. |
| 9 | */ |
| 10 | |
| 11 | package org.osgi.framework; |
| 12 | |
| 13 | import java.io.IOException; |
| 14 | import java.io.InputStream; |
| 15 | import java.security.*; |
| 16 | import java.util.*; |
Richard S. Hall | 5a03159 | 2005-08-19 19:53:58 +0000 | [diff] [blame^] | 17 | import org.apache.felix.framework.FilterImpl; |
Richard S. Hall | 930fecc | 2005-08-16 18:33:34 +0000 | [diff] [blame] | 18 | |
| 19 | /** |
| 20 | * Indicates the caller's authority to perform specific privileged administrative |
| 21 | * operations on or to get sensitive information about a bundle. |
| 22 | * |
| 23 | * <ul> |
| 24 | * <li>The <code>{@link AdminPermission#METADATA}</code> action allows calls to |
| 25 | * <ul> |
| 26 | * <li>{@link Bundle#getHeaders()} |
| 27 | * <li>{@link Bundle#getHeaders(String)} |
| 28 | * <li>{@link Bundle#getLocation()} |
| 29 | * </ul> |
| 30 | * <li>The <code>{@link AdminPermission#RESOURCE}</code> action allows calls to |
| 31 | * <ul> |
| 32 | * <li>{@link Bundle#getResource(String)} |
| 33 | * <li>{@link Bundle#getEntry(String)} |
| 34 | * <li>{@link Bundle#getEntryPaths(String)} |
| 35 | * <li>Bundle resource/entry URL creation |
| 36 | * </ul> |
| 37 | * <li>The <code>{@link AdminPermission#METADATA}</code> action allows calls to |
| 38 | * <ul> |
| 39 | * <li>{@link Bundle#loadClass(String)} |
| 40 | * </ul> |
| 41 | * <li>The <code>{@link AdminPermission#LIFECYCLE}</code> action allows calls to |
| 42 | * <ul> |
| 43 | * <li>{@link BundleContext#installBundle(String)} |
| 44 | * <li>{@link BundleContext#installBundle(String, InputStream)} |
| 45 | * <li>{@link Bundle#update()} |
| 46 | * <li>{@link Bundle#update(InputStream)} |
| 47 | * <li>{@link Bundle#uninstall()} |
| 48 | * </ul> |
| 49 | * <li>The <code>{@link AdminPermission#EXECUTE}</code> action allows calls to |
| 50 | * <ul> |
| 51 | * <li>{@link Bundle#start()} |
| 52 | * <li>{@link Bundle#stop()} |
| 53 | * <li>{@link org.osgi.service.startlevel.StartLevel#setBundleStartLevel(Bundle, int)} |
| 54 | * </ul> |
| 55 | * <li>The <code>{@link AdminPermission#LISTENER}</code> action allows calls to |
| 56 | * <ul> |
| 57 | * <li>{@link BundleContext#addBundleListener(BundleListener)} for |
| 58 | * <code>SynchronousBundleListener</code> |
| 59 | * <li>{@link BundleContext#removeBundleListener(BundleListener)} for |
| 60 | * <code>SynchronousBundleListener</code> |
| 61 | * </ul> |
| 62 | * <li>The <code>{@link AdminPermission#PERMISSION}</code> action allows calls to |
| 63 | * <ul> |
| 64 | * <li>{@link org.osgi.service.permissionadmin.PermissionAdmin#setPermissions(String, PermissionInfo[])} |
| 65 | * <li>{@link org.osgi.service.permissionadmin.PermissionAdmin#setDefaultPermissions(PermissionInfo[])} |
| 66 | * </ul> |
| 67 | * <li>The <code>{@link AdminPermission#RESOLVE}</code> action allows calls to |
| 68 | * <ul> |
| 69 | * <li>{@link org.osgi.service.packageadmin.PackageAdmin#refreshPackages(Bundle[])}</code> |
| 70 | * <li>{@link org.osgi.service.packageadmin.PackageAdmin#resolveBundles(Bundle[])}</code> |
| 71 | * </ul> |
| 72 | * <li>The <code>{@link AdminPermission#STARTLEVEL}</code> action allows calls to |
| 73 | * <ul> |
| 74 | * <li>{@link org.osgi.service.startlevel.StartLevel#setStartLevel(int)} |
| 75 | * <li>{@link org.osgi.service.startlevel.StartLevel#setInitialBundleStartLevel(int)} |
| 76 | * </ul> |
| 77 | * </ul> |
| 78 | * |
| 79 | * The special action "*" will represent all actions. |
| 80 | * |
| 81 | * @version $Revision: 1.12 $ |
| 82 | */ |
| 83 | |
| 84 | public final class AdminPermission extends Permission |
| 85 | { |
| 86 | static final long serialVersionUID = 207051004521261705L; |
| 87 | |
| 88 | /** |
| 89 | * The action string <code>class</code> (Value is "class"). |
| 90 | */ |
| 91 | public final static String CLASS = "class"; //$NON-NLS-1$ |
| 92 | |
| 93 | /** |
| 94 | * The action string <code>execute</code> (Value is "execute"). |
| 95 | */ |
| 96 | public final static String EXECUTE = "execute"; //$NON-NLS-1$ |
| 97 | |
| 98 | /** |
| 99 | * The action string <code>lifecycle</code> (Value is "lifecycle"). |
| 100 | */ |
| 101 | public final static String LIFECYCLE = "lifecycle"; //$NON-NLS-1$ |
| 102 | |
| 103 | /** |
| 104 | * The action string <code>listener</code> (Value is "listener"). |
| 105 | */ |
| 106 | public final static String LISTENER = "listener"; //$NON-NLS-1$ |
| 107 | |
| 108 | /** |
| 109 | * The action string <code>metadata</code> (Value is "metadata"). |
| 110 | */ |
| 111 | public final static String METADATA = "metadata"; //$NON-NLS-1$ |
| 112 | |
| 113 | /** |
| 114 | * The action string <code>permission</code> (Value is "permission"). |
| 115 | */ |
| 116 | public final static String PERMISSION = "permission"; //$NON-NLS-1$ |
| 117 | |
| 118 | /** |
| 119 | * The action string <code>resolve</code> (Value is "resolve"). |
| 120 | */ |
| 121 | public final static String RESOLVE = "resolve"; //$NON-NLS-1$ |
| 122 | |
| 123 | /** |
| 124 | * The action string <code>resource</code> (Value is "resource"). |
| 125 | */ |
| 126 | public final static String RESOURCE = "resource"; //$NON-NLS-1$ |
| 127 | |
| 128 | /** |
| 129 | * The action string <code>startlevel</code> (Value is "startlevel"). |
| 130 | */ |
| 131 | public final static String STARTLEVEL = "startlevel"; //$NON-NLS-1$ |
| 132 | |
| 133 | /** |
| 134 | * The action string <code>extensionLifecycle</code> (Value is "extensionLifecycle"). |
| 135 | */ |
| 136 | public final static String EXTENSIONLIFECYCLE = "extensionLifecycle"; //$NON-NLS-1$ |
| 137 | |
| 138 | private final static int ACTION_CLASS = 0x00000001; |
| 139 | private final static int ACTION_EXECUTE = 0x00000002; |
| 140 | private final static int ACTION_LIFECYCLE = 0x00000004; |
| 141 | private final static int ACTION_LISTENER = 0x00000008; |
| 142 | private final static int ACTION_METADATA = 0x00000010; |
| 143 | private final static int ACTION_PERMISSION = 0x00000020; |
| 144 | private final static int ACTION_RESOLVE = 0x00000040; |
| 145 | private final static int ACTION_RESOURCE = 0x00000080; |
| 146 | private final static int ACTION_STARTLEVEL = 0x00000100; |
| 147 | private final static int ACTION_EXTENSIONLIFECYCLE = 0x00000200; |
| 148 | private final static int ACTION_ALL = |
| 149 | ACTION_CLASS | |
| 150 | ACTION_EXECUTE | |
| 151 | ACTION_LIFECYCLE | |
| 152 | ACTION_LISTENER | |
| 153 | ACTION_METADATA | |
| 154 | ACTION_PERMISSION | |
| 155 | ACTION_RESOLVE | |
| 156 | ACTION_RESOURCE | |
| 157 | ACTION_STARTLEVEL | |
| 158 | ACTION_EXTENSIONLIFECYCLE; |
| 159 | private final static int ACTION_NONE = 0; |
| 160 | |
| 161 | /** |
| 162 | * Indicates that this AdminPermission refers to all bundles |
| 163 | * @serial |
| 164 | */ |
| 165 | private boolean wildcard; |
| 166 | |
| 167 | /** |
| 168 | * An x.500 distinguished name used to match a bundle's signature - only used if |
| 169 | * wildcard is false and bundle = null |
| 170 | * @serial |
| 171 | */ |
| 172 | private String filter; |
| 173 | |
| 174 | /** |
| 175 | * The actions in canonical form. |
| 176 | * |
| 177 | * @serial |
| 178 | */ |
| 179 | private String actions = null; |
| 180 | |
| 181 | /** |
| 182 | * The actions mask. |
| 183 | */ |
| 184 | private transient int action_mask = ACTION_NONE; |
| 185 | |
| 186 | /** |
| 187 | * The bundle governed by this AdminPermission - only used if |
| 188 | * wildcard is false and filter == null |
| 189 | */ |
| 190 | private transient Bundle bundle; |
| 191 | |
| 192 | /** |
| 193 | * If this AdminPermission was constructed with a bundle, this dictionary holds |
| 194 | * the properties of that bundle, used to match a filter in implies. |
| 195 | * This is not initialized until necessary, and then cached in this object. |
| 196 | */ |
| 197 | private transient Dictionary bundleProperties; |
| 198 | |
| 199 | /** |
| 200 | * If this AdminPermission was constructed with a filter, this dictionary holds |
| 201 | * a Filter matching object used to evaluate the filter in implies. |
| 202 | * This is not initialized until necessary, and then cached in this object |
| 203 | */ |
| 204 | private transient Filter filterImpl; |
| 205 | |
| 206 | /** |
| 207 | * Creates a new <code>AdminPermission</code> object that matches |
| 208 | * all bundles and has all actions. Equivalent to |
| 209 | * AdminPermission("*","*"); |
| 210 | */ |
| 211 | public AdminPermission() |
| 212 | { |
| 213 | this("*",AdminPermission.ACTION_ALL); //$NON-NLS-1$ |
| 214 | } |
| 215 | |
| 216 | /** |
| 217 | * Creates a new <code>AdminPermission</code> object for use by the <code>Policy</code> |
| 218 | * object to instantiate new <code>Permission</code> objects. |
| 219 | * |
| 220 | * Null arguments are equivalent to "*" |
| 221 | * |
| 222 | * @param filter an X.500 Distinguished Name suffix or "*" to match all bundles |
| 223 | * @param actions <code>class</code>, <code>execute</code>, <code>lifecycle</code>, |
| 224 | * <code>listener</code>, <code>metadata</code>, <code>permission</code>, <code>resolve</code>, |
| 225 | * <code>resource</code>, <code>startlevel</code>, or "*" to indicate all actions |
| 226 | */ |
| 227 | public AdminPermission(String filter, String actions) |
| 228 | { |
| 229 | //arguments will be null if called from a PermissionInfo defined with |
| 230 | //no args |
| 231 | this( |
| 232 | (filter == null ? "*" : filter), //$NON-NLS-1$ |
| 233 | getMask((actions == null ? "*" : actions)) //$NON-NLS-1$ |
| 234 | ); |
| 235 | } |
| 236 | |
| 237 | /** |
| 238 | * Creates a new <code>AdminPermission</code> object for use by the <code>Policy</code> |
| 239 | * object to instantiate new <code>Permission</code> objects. |
| 240 | * |
| 241 | * @param bundle A bundle |
| 242 | * @param actions <code>class</code>, <code>execute</code>, <code>lifecycle</code>, |
| 243 | * <code>listener</code>, <code>metadata</code>, <code>permission</code>, <code>resolve</code>, |
| 244 | * <code>resource</code>, <code>startlevel</code>, or "*" to indicate all actions |
| 245 | */ |
| 246 | public AdminPermission(Bundle bundle, String actions) { |
| 247 | super(bundle.toString()); |
| 248 | this.bundle = bundle; |
| 249 | this.wildcard = false; |
| 250 | this.filter = null; |
| 251 | this.action_mask = getMask(actions); |
| 252 | } |
| 253 | |
| 254 | /** |
| 255 | * Package private constructor used by AdminPermissionCollection. |
| 256 | * |
| 257 | * @param filter name filter |
| 258 | * @param action_mask mask |
| 259 | */ |
| 260 | AdminPermission(String filter, int action_mask) { |
| 261 | super(filter); |
| 262 | |
| 263 | //name must be either * or a filter |
| 264 | if (filter.equals("*")) { //$NON-NLS-1$ |
| 265 | this.wildcard = true; |
| 266 | this.filter = null; |
| 267 | } else { |
| 268 | this.wildcard = false; |
| 269 | this.filter = filter; |
| 270 | } |
| 271 | this.bundle = null; |
| 272 | this.action_mask = action_mask; |
| 273 | } |
| 274 | |
| 275 | /** |
| 276 | * Parse action string into action mask. |
| 277 | * |
| 278 | * @param actions Action string. |
| 279 | * @return action mask. |
| 280 | */ |
| 281 | private static int getMask(String actions) { |
| 282 | |
| 283 | boolean seencomma = false; |
| 284 | |
| 285 | int mask = ACTION_NONE; |
| 286 | |
| 287 | if (actions == null) { |
| 288 | return mask; |
| 289 | } |
| 290 | |
| 291 | char[] a = actions.toCharArray(); |
| 292 | |
| 293 | int i = a.length - 1; |
| 294 | if (i < 0) |
| 295 | return mask; |
| 296 | |
| 297 | while (i != -1) { |
| 298 | char c; |
| 299 | |
| 300 | // skip whitespace |
| 301 | while ((i!=-1) && ((c = a[i]) == ' ' || |
| 302 | c == '\r' || |
| 303 | c == '\n' || |
| 304 | c == '\f' || |
| 305 | c == '\t')) |
| 306 | i--; |
| 307 | |
| 308 | // check for the known strings |
| 309 | int matchlen; |
| 310 | |
| 311 | if (i >= 4 && |
| 312 | (a[i-4] == 'c' || a[i-4] == 'C') && |
| 313 | (a[i-3] == 'l' || a[i-3] == 'L') && |
| 314 | (a[i-2] == 'a' || a[i-2] == 'A') && |
| 315 | (a[i-1] == 's' || a[i-1] == 'S') && |
| 316 | (a[i] == 's' || a[i] == 'S')) |
| 317 | { |
| 318 | matchlen = 5; |
| 319 | mask |= ACTION_CLASS; |
| 320 | |
| 321 | } else if (i >= 6 && |
| 322 | (a[i-6] == 'e' || a[i-6] == 'E') && |
| 323 | (a[i-5] == 'x' || a[i-5] == 'X') && |
| 324 | (a[i-4] == 'e' || a[i-4] == 'E') && |
| 325 | (a[i-3] == 'c' || a[i-3] == 'C') && |
| 326 | (a[i-2] == 'u' || a[i-2] == 'U') && |
| 327 | (a[i-1] == 't' || a[i-1] == 'T') && |
| 328 | (a[i] == 'e' || a[i] == 'E')) |
| 329 | { |
| 330 | matchlen = 7; |
| 331 | mask |= ACTION_EXECUTE; |
| 332 | |
| 333 | } else if (i >= 17 && |
| 334 | (a[i-17] == 'e' || a[i-17] == 'E') && |
| 335 | (a[i-16] == 'x' || a[i-16] == 'X') && |
| 336 | (a[i-15] == 't' || a[i-15] == 'T') && |
| 337 | (a[i-14] == 'e' || a[i-14] == 'E') && |
| 338 | (a[i-13] == 'n' || a[i-13] == 'N') && |
| 339 | (a[i-12] == 's' || a[i-12] == 'S') && |
| 340 | (a[i-11] == 'i' || a[i-11] == 'I') && |
| 341 | (a[i-10] == 'o' || a[i-10] == 'O') && |
| 342 | (a[i-9] == 'n' || a[i-9] == 'N') && |
| 343 | (a[i-8] == 'l' || a[i-8] == 'L') && |
| 344 | (a[i-7] == 'i' || a[i-7] == 'I') && |
| 345 | (a[i-6] == 'f' || a[i-6] == 'F') && |
| 346 | (a[i-5] == 'e' || a[i-5] == 'E') && |
| 347 | (a[i-4] == 'c' || a[i-4] == 'C') && |
| 348 | (a[i-3] == 'y' || a[i-3] == 'Y') && |
| 349 | (a[i-2] == 'c' || a[i-2] == 'C') && |
| 350 | (a[i-1] == 'l' || a[i-1] == 'L') && |
| 351 | (a[i] == 'e' || a[i] == 'E')) |
| 352 | { |
| 353 | matchlen = 18; |
| 354 | mask |= ACTION_EXTENSIONLIFECYCLE; |
| 355 | |
| 356 | } else if (i >= 8 && |
| 357 | (a[i-8] == 'l' || a[i-8] == 'L') && |
| 358 | (a[i-7] == 'i' || a[i-7] == 'I') && |
| 359 | (a[i-6] == 'f' || a[i-6] == 'F') && |
| 360 | (a[i-5] == 'e' || a[i-5] == 'E') && |
| 361 | (a[i-4] == 'c' || a[i-4] == 'C') && |
| 362 | (a[i-3] == 'y' || a[i-3] == 'Y') && |
| 363 | (a[i-2] == 'c' || a[i-2] == 'C') && |
| 364 | (a[i-1] == 'l' || a[i-1] == 'L') && |
| 365 | (a[i] == 'e' || a[i] == 'E')) |
| 366 | { |
| 367 | matchlen = 9; |
| 368 | mask |= ACTION_LIFECYCLE; |
| 369 | |
| 370 | } else if (i >= 7 && |
| 371 | (a[i-7] == 'l' || a[i-7] == 'L') && |
| 372 | (a[i-6] == 'i' || a[i-6] == 'I') && |
| 373 | (a[i-5] == 's' || a[i-5] == 'S') && |
| 374 | (a[i-4] == 't' || a[i-4] == 'T') && |
| 375 | (a[i-3] == 'e' || a[i-3] == 'E') && |
| 376 | (a[i-2] == 'n' || a[i-2] == 'N') && |
| 377 | (a[i-1] == 'e' || a[i-1] == 'E') && |
| 378 | (a[i] == 'r' || a[i] == 'R')) |
| 379 | { |
| 380 | matchlen = 8; |
| 381 | mask |= ACTION_LISTENER; |
| 382 | |
| 383 | } else if (i >= 7 && |
| 384 | (a[i-7] == 'm' || a[i-7] == 'M') && |
| 385 | (a[i-6] == 'e' || a[i-6] == 'E') && |
| 386 | (a[i-5] == 't' || a[i-5] == 'T') && |
| 387 | (a[i-4] == 'a' || a[i-4] == 'A') && |
| 388 | (a[i-3] == 'd' || a[i-3] == 'D') && |
| 389 | (a[i-2] == 'a' || a[i-2] == 'A') && |
| 390 | (a[i-1] == 't' || a[i-1] == 'T') && |
| 391 | (a[i] == 'a' || a[i] == 'A')) |
| 392 | { |
| 393 | matchlen = 8; |
| 394 | mask |= ACTION_METADATA; |
| 395 | |
| 396 | } else if (i >= 9 && |
| 397 | (a[i-9] == 'p' || a[i-9] == 'P') && |
| 398 | (a[i-8] == 'e' || a[i-8] == 'E') && |
| 399 | (a[i-7] == 'r' || a[i-7] == 'R') && |
| 400 | (a[i-6] == 'm' || a[i-6] == 'M') && |
| 401 | (a[i-5] == 'i' || a[i-5] == 'I') && |
| 402 | (a[i-4] == 's' || a[i-4] == 'S') && |
| 403 | (a[i-3] == 's' || a[i-3] == 'S') && |
| 404 | (a[i-2] == 'i' || a[i-2] == 'I') && |
| 405 | (a[i-1] == 'o' || a[i-1] == 'O') && |
| 406 | (a[i] == 'n' || a[i] == 'N')) |
| 407 | { |
| 408 | matchlen = 10; |
| 409 | mask |= ACTION_PERMISSION; |
| 410 | |
| 411 | } else if (i >= 6 && |
| 412 | (a[i-6] == 'r' || a[i-6] == 'R') && |
| 413 | (a[i-5] == 'e' || a[i-5] == 'E') && |
| 414 | (a[i-4] == 's' || a[i-4] == 'S') && |
| 415 | (a[i-3] == 'o' || a[i-3] == 'O') && |
| 416 | (a[i-2] == 'l' || a[i-2] == 'L') && |
| 417 | (a[i-1] == 'v' || a[i-1] == 'V') && |
| 418 | (a[i] == 'e' || a[i] == 'E')) |
| 419 | { |
| 420 | matchlen = 7; |
| 421 | mask |= ACTION_RESOLVE; |
| 422 | |
| 423 | } else if (i >= 7 && |
| 424 | (a[i-7] == 'r' || a[i-7] == 'R') && |
| 425 | (a[i-6] == 'e' || a[i-6] == 'E') && |
| 426 | (a[i-5] == 's' || a[i-5] == 'S') && |
| 427 | (a[i-4] == 'o' || a[i-4] == 'O') && |
| 428 | (a[i-3] == 'u' || a[i-3] == 'U') && |
| 429 | (a[i-2] == 'r' || a[i-2] == 'R') && |
| 430 | (a[i-1] == 'c' || a[i-1] == 'C') && |
| 431 | (a[i] == 'e' || a[i] == 'E')) |
| 432 | { |
| 433 | matchlen = 8; |
| 434 | mask |= ACTION_RESOURCE; |
| 435 | |
| 436 | } else if (i >= 9 && |
| 437 | (a[i-9] == 's' || a[i-9] == 'S') && |
| 438 | (a[i-8] == 't' || a[i-8] == 'T') && |
| 439 | (a[i-7] == 'a' || a[i-7] == 'A') && |
| 440 | (a[i-6] == 'r' || a[i-6] == 'R') && |
| 441 | (a[i-5] == 't' || a[i-5] == 'T') && |
| 442 | (a[i-4] == 'l' || a[i-4] == 'L') && |
| 443 | (a[i-3] == 'e' || a[i-3] == 'E') && |
| 444 | (a[i-2] == 'v' || a[i-2] == 'V') && |
| 445 | (a[i-1] == 'e' || a[i-1] == 'E') && |
| 446 | (a[i] == 'l' || a[i] == 'L')) |
| 447 | { |
| 448 | matchlen = 10; |
| 449 | mask |= ACTION_STARTLEVEL; |
| 450 | |
| 451 | } else if (i >= 0 && |
| 452 | (a[i] == '*')) |
| 453 | { |
| 454 | matchlen = 1; |
| 455 | mask |= ACTION_ALL; |
| 456 | |
| 457 | } else { |
| 458 | // parse error |
| 459 | throw new IllegalArgumentException( |
| 460 | "invalid permission: " + actions); |
| 461 | } |
| 462 | |
| 463 | // make sure we didn't just match the tail of a word |
| 464 | // like "ackbarfstartlevel". Also, skip to the comma. |
| 465 | seencomma = false; |
| 466 | while (i >= matchlen && !seencomma) { |
| 467 | switch(a[i-matchlen]) { |
| 468 | case ',': |
| 469 | seencomma = true; |
| 470 | /*FALLTHROUGH*/ |
| 471 | case ' ': case '\r': case '\n': |
| 472 | case '\f': case '\t': |
| 473 | break; |
| 474 | default: |
| 475 | throw new IllegalArgumentException( |
| 476 | "invalid permission: " + actions); |
| 477 | } |
| 478 | i--; |
| 479 | } |
| 480 | |
| 481 | // point i at the location of the comma minus one (or -1). |
| 482 | i -= matchlen; |
| 483 | } |
| 484 | |
| 485 | if (seencomma) { |
| 486 | throw new IllegalArgumentException("invalid permission: " + |
| 487 | actions); |
| 488 | } |
| 489 | |
| 490 | return mask; |
| 491 | } |
| 492 | |
| 493 | /** |
| 494 | * Called by <code><@link AdminPermission#implies(Permission)></code> on an AdminPermission |
| 495 | * which was constructed with a Bundle. This method loads a dictionary with the |
| 496 | * filter-matchable properties of this bundle. The dictionary is cached so this lookup |
| 497 | * only happens once. |
| 498 | * |
| 499 | * This method should only be called on an AdminPermission which was constructed with a |
| 500 | * bundle |
| 501 | * |
| 502 | * @return a dictionary of properties for this bundle |
| 503 | */ |
| 504 | private Dictionary getProperties() { |
| 505 | if (bundleProperties == null) { |
| 506 | bundleProperties = new Hashtable(); |
| 507 | |
| 508 | AccessController.doPrivileged(new PrivilegedAction() { |
| 509 | public Object run() { |
| 510 | //set Id |
| 511 | bundleProperties.put("id",new Long(bundle.getBundleId())); //$NON-NLS-1$ |
| 512 | |
| 513 | //set location |
| 514 | bundleProperties.put("location",bundle.getLocation()); //$NON-NLS-1$ |
| 515 | |
| 516 | //set name |
| 517 | if (bundle.getSymbolicName() != null) |
| 518 | bundleProperties.put("name",bundle.getSymbolicName()); //$NON-NLS-1$ |
| 519 | |
| 520 | //set signers |
| 521 | // bundleProperties.put("signer",new SignerWrapper(bundle)); //$NON-NLS-1$ |
| 522 | |
| 523 | return null; |
| 524 | } |
| 525 | }); |
| 526 | } |
| 527 | return bundleProperties; |
| 528 | } |
| 529 | /* |
| 530 | private static class SignerWrapper extends Object { |
| 531 | private Bundle bundle; |
| 532 | private String pattern; |
| 533 | public SignerWrapper(String pattern) { |
| 534 | this.pattern = pattern; |
| 535 | } |
| 536 | SignerWrapper(Bundle bundle) { |
| 537 | this.bundle = bundle; |
| 538 | } |
| 539 | |
| 540 | public boolean equals(Object o) { |
| 541 | if (!(o instanceof SignerWrapper)) |
| 542 | return false; |
| 543 | SignerWrapper other = (SignerWrapper) o; |
| 544 | AbstractBundle matchBundle = (AbstractBundle) (bundle != null ? bundle : other.bundle); |
| 545 | String matchPattern = bundle != null ? other.pattern : pattern; |
| 546 | return matchBundle.getBundleData().matchDNChain(matchPattern); |
| 547 | } |
| 548 | } |
| 549 | */ |
| 550 | |
| 551 | /** |
| 552 | * Called by <tt><@link AdminPermission#implies(Permission)></tt> on an AdminPermission |
| 553 | * which was constructed with a filter. This method loads a FilterImpl with the |
| 554 | * filter specification of this AdminPermission. The filter is cached so this work |
| 555 | * only happens once. |
| 556 | * |
| 557 | * This method should only be called on an AdminPermission which was constructed with a |
| 558 | * filter |
| 559 | * |
| 560 | * @return a filterImpl for this bundle |
| 561 | */ |
| 562 | private Filter getFilterImpl() { |
| 563 | if (filterImpl == null) { |
| 564 | try { |
| 565 | int pos = filter.indexOf("signer"); //$NON-NLS-1$ |
| 566 | if (pos != -1){ |
| 567 | |
| 568 | //there may be a signer attribute |
| 569 | StringBuffer filterBuf = new StringBuffer(filter); |
| 570 | int numAsteriskFound = 0; //use as offset to replace in buffer |
| 571 | |
| 572 | int walkbackPos; //temp pos |
| 573 | |
| 574 | //find occurences of (signer= and escape out *'s |
| 575 | while (pos != -1) { |
| 576 | |
| 577 | //walk back and look for '(' to see if this is an attr |
| 578 | walkbackPos = pos-1; |
| 579 | |
| 580 | //consume whitespace |
| 581 | while(walkbackPos >= 0 && Character.isWhitespace(filter.charAt(walkbackPos))) { |
| 582 | walkbackPos--; |
| 583 | } |
| 584 | if (walkbackPos <0) { |
| 585 | //filter is invalid - FilterImpl will throw error |
| 586 | break; |
| 587 | } |
| 588 | |
| 589 | //check to see if we have unescaped '(' |
| 590 | if (filter.charAt(walkbackPos) != '(' || (walkbackPos > 0 && filter.charAt(walkbackPos-1) == '\\')) { |
| 591 | //'(' was escaped or not there |
| 592 | pos = filter.indexOf("signer",pos+6); //$NON-NLS-1$ |
| 593 | continue; |
| 594 | } |
| 595 | pos+=6; //skip over 'signer' |
| 596 | |
| 597 | //found signer - consume whitespace before '=' |
| 598 | while (Character.isWhitespace(filter.charAt(pos))) { |
| 599 | pos++; |
| 600 | } |
| 601 | |
| 602 | //look for '=' |
| 603 | if (filter.charAt(pos) != '=') { |
| 604 | //attr was signerx - keep looking |
| 605 | pos = filter.indexOf("signer",pos); //$NON-NLS-1$ |
| 606 | continue; |
| 607 | } |
| 608 | pos++; //skip over '=' |
| 609 | |
| 610 | //found signer value - escape '*'s |
| 611 | while (!(filter.charAt(pos) == ')' && filter.charAt(pos-1) != '\\')) { |
| 612 | if (filter.charAt(pos) == '*') { |
| 613 | filterBuf.insert(pos+numAsteriskFound,'\\'); |
| 614 | numAsteriskFound++; |
| 615 | } |
| 616 | pos++; |
| 617 | } |
| 618 | |
| 619 | //end of signer value - look for more? |
| 620 | pos = filter.indexOf("signer",pos); //$NON-NLS-1$ |
| 621 | } //end while (pos != -1) |
| 622 | filter = filterBuf.toString(); |
| 623 | } //end if (pos != -1) |
| 624 | |
| 625 | filterImpl = new FilterImpl(filter); |
| 626 | } catch (InvalidSyntaxException e) { |
| 627 | //we will return null |
| 628 | } |
| 629 | } |
| 630 | return filterImpl; |
| 631 | } |
| 632 | |
| 633 | /** |
| 634 | * Determines if the specified permission is implied by this object. |
| 635 | * This method throws an exception if the specified permission was not |
| 636 | * constructed with a bundle. |
| 637 | * |
| 638 | * <p>This method returns <code>true</code> if |
| 639 | * The specified permission is an AdminPermission AND |
| 640 | * <ul> |
| 641 | * <li>this object's filter is an X.500 Distinguished name suffix that |
| 642 | * matches the specified permission's bundle OR |
| 643 | * <li>this object's filter is "*" OR |
| 644 | * <li>this object's bundle is a equal to the specified permission's |
| 645 | * bundle |
| 646 | * </ul> |
| 647 | * AND this object's actions include all of the specified permission's actions |
| 648 | * |
| 649 | * Special case: if the specified permission was constructed with "*", then this method |
| 650 | * returns <code>true</code> if this object's filter is "*" and this object's actions include |
| 651 | * all of the specified permission's actions |
| 652 | * |
| 653 | * @param p The permission to interrogate. |
| 654 | * |
| 655 | * @return <code>true</code> if the specified permission is implied by |
| 656 | * this object; <code>false</code> otherwise. |
| 657 | * @throws RuntimeException if specified permission was not constructed with |
| 658 | * a bundle or "*" |
| 659 | */ |
| 660 | public boolean implies(Permission p) |
| 661 | { |
| 662 | if (!(p instanceof AdminPermission)) |
| 663 | return false; |
| 664 | AdminPermission target = (AdminPermission)p; |
| 665 | //check actions first - much faster |
| 666 | if ((action_mask & target.action_mask)!=target.action_mask) |
| 667 | return false; |
| 668 | //if passed in a filter, puke |
| 669 | if (target.filter != null) |
| 670 | throw new RuntimeException("Cannot imply a filter"); |
| 671 | //special case - only wildcard implies wildcard |
| 672 | if (target.wildcard) |
| 673 | return wildcard; |
| 674 | |
| 675 | //check our name |
| 676 | if (filter != null) { |
| 677 | //it's a filter |
| 678 | Filter filterImpl = getFilterImpl(); |
| 679 | return filterImpl != null && filterImpl.match(target.getProperties()); |
| 680 | } else if (wildcard) { |
| 681 | //it's "*" |
| 682 | return true; |
| 683 | } else { |
| 684 | //it's a bundle id |
| 685 | return bundle.equals(target.bundle); |
| 686 | } |
| 687 | |
| 688 | } |
| 689 | |
| 690 | /** |
| 691 | * Returns the canonical string representation of the <code>AdminPermission</code> actions. |
| 692 | * |
| 693 | * <p>Always returns present <code>AdminPermission</code> actions in the following order: |
| 694 | * <code>CLASS</code>, <code>EXECUTE</code>, <code>LIFECYCLE</code>, <code>LISTENER</code>, |
| 695 | * <code>METADATA</code>, <code>PERMISSION</code>, <code>RESOLVE</code>, <code>RESOURCE</code>, |
| 696 | * <code>STARTLEVEL</code>. |
| 697 | * @return Canonical string representation of the <code>AdminPermission</code> actions. |
| 698 | */ |
| 699 | public String getActions() { |
| 700 | if (actions == null) { |
| 701 | if (action_mask == ACTION_ALL) { |
| 702 | actions = "*"; //$NON-NLS-1$ |
| 703 | } else { |
| 704 | StringBuffer sb = new StringBuffer(); |
| 705 | |
| 706 | if ((action_mask & ACTION_CLASS) == ACTION_CLASS) { |
| 707 | sb.append(CLASS); |
| 708 | sb.append(','); |
| 709 | } |
| 710 | |
| 711 | if ((action_mask & ACTION_EXECUTE) == ACTION_EXECUTE) { |
| 712 | sb.append(EXECUTE); |
| 713 | sb.append(','); |
| 714 | } |
| 715 | |
| 716 | if ((action_mask & ACTION_LIFECYCLE) == ACTION_LIFECYCLE) { |
| 717 | sb.append(LIFECYCLE); |
| 718 | sb.append(','); |
| 719 | } |
| 720 | |
| 721 | if ((action_mask & ACTION_LISTENER) == ACTION_LISTENER) { |
| 722 | sb.append(LISTENER); |
| 723 | sb.append(','); |
| 724 | } |
| 725 | |
| 726 | if ((action_mask & ACTION_METADATA) == ACTION_METADATA) { |
| 727 | sb.append(METADATA); |
| 728 | sb.append(','); |
| 729 | } |
| 730 | |
| 731 | if ((action_mask & ACTION_PERMISSION) == ACTION_PERMISSION) { |
| 732 | sb.append(PERMISSION); |
| 733 | sb.append(','); |
| 734 | } |
| 735 | |
| 736 | if ((action_mask & ACTION_RESOLVE) == ACTION_RESOLVE) { |
| 737 | sb.append(RESOLVE); |
| 738 | sb.append(','); |
| 739 | } |
| 740 | |
| 741 | if ((action_mask & ACTION_RESOURCE) == ACTION_RESOURCE) { |
| 742 | sb.append(RESOURCE); |
| 743 | sb.append(','); |
| 744 | } |
| 745 | |
| 746 | if ((action_mask & ACTION_STARTLEVEL) == ACTION_STARTLEVEL) { |
| 747 | sb.append(STARTLEVEL); |
| 748 | sb.append(','); |
| 749 | } |
| 750 | |
| 751 | if ((action_mask & ACTION_EXTENSIONLIFECYCLE) == ACTION_EXTENSIONLIFECYCLE) { |
| 752 | sb.append(EXTENSIONLIFECYCLE); |
| 753 | sb.append(','); |
| 754 | } |
| 755 | |
| 756 | //remove trailing comma |
| 757 | if (sb.length() > 0) { |
| 758 | sb.deleteCharAt(sb.length()-1); |
| 759 | } |
| 760 | |
| 761 | actions = sb.toString(); |
| 762 | } |
| 763 | } |
| 764 | return actions; |
| 765 | } |
| 766 | |
| 767 | /** |
| 768 | * Determines the equality of two <code>AdminPermission</code> objects. <p>Two |
| 769 | * <code>AdminPermission</code> objects are equal. |
| 770 | * |
| 771 | * @param obj The object being compared for equality with this object. |
| 772 | * @return <code>true</code> if <code>obj</code> is equivalent to this |
| 773 | * <code>AdminPermission</code>; <code>false</code> otherwise. |
| 774 | */ |
| 775 | public boolean equals(Object obj) |
| 776 | { |
| 777 | if (obj == this) { |
| 778 | return true; |
| 779 | } |
| 780 | |
| 781 | if (!(obj instanceof AdminPermission)) |
| 782 | { |
| 783 | return false; |
| 784 | } |
| 785 | |
| 786 | AdminPermission a = (AdminPermission) obj; |
| 787 | |
| 788 | return (action_mask == a.action_mask) && |
| 789 | (wildcard == a.wildcard) && |
| 790 | (bundle == null ? a.bundle == null : (a.bundle == null ? false : bundle.getBundleId() == a.bundle.getBundleId())) && |
| 791 | (filter == null ? a.filter == null : filter.equals(a.filter)); |
| 792 | } |
| 793 | |
| 794 | /** |
| 795 | * Returns the hash code value for this object. |
| 796 | * |
| 797 | * @return Hash code value for this object. |
| 798 | */ |
| 799 | public int hashCode() { |
| 800 | return getName().hashCode() ^ getActions().hashCode(); |
| 801 | } |
| 802 | |
| 803 | private synchronized void writeObject(java.io.ObjectOutputStream s) throws IOException { |
| 804 | // Write out the actions. The superclass takes care of the name |
| 805 | // call getActions to make sure actions field is initialized |
| 806 | if (actions == null) |
| 807 | getActions(); |
| 808 | if (filter == null && !wildcard) |
| 809 | throw new UnsupportedOperationException("cannot serialize"); |
| 810 | s.defaultWriteObject(); |
| 811 | } |
| 812 | |
| 813 | /** |
| 814 | * readObject is called to restore the state of this permission from a |
| 815 | * stream. |
| 816 | */ |
| 817 | private synchronized void readObject(java.io.ObjectInputStream s) throws IOException, ClassNotFoundException { |
| 818 | // Read in the action, then initialize the rest |
| 819 | s.defaultReadObject(); |
| 820 | action_mask = getMask(actions); |
| 821 | } |
| 822 | |
| 823 | /** |
| 824 | * Returns a new <code>PermissionCollection</code> object suitable for storing |
| 825 | * <code>AdminPermission</code>s. |
| 826 | * |
| 827 | * @return A new <code>PermissionCollection</code> object. |
| 828 | */ |
| 829 | public PermissionCollection newPermissionCollection() |
| 830 | { |
| 831 | return(new AdminPermissionCollection()); |
| 832 | } |
| 833 | |
| 834 | /** |
| 835 | * Stores a collection of <code>AdminPermission</code>s. |
| 836 | */ |
| 837 | private final class AdminPermissionCollection extends PermissionCollection |
| 838 | { |
| 839 | private static final long serialVersionUID = 3906372644575328048L; |
| 840 | /** |
| 841 | * Collection of permissions. |
| 842 | * |
| 843 | * @serial |
| 844 | */ |
| 845 | private Hashtable permissions; |
| 846 | |
| 847 | /** |
| 848 | * Create an empty AdminPermissions object. |
| 849 | * |
| 850 | */ |
| 851 | |
| 852 | public AdminPermissionCollection() |
| 853 | { |
| 854 | permissions = new Hashtable(); |
| 855 | } |
| 856 | |
| 857 | /** |
| 858 | * Adds a permission to the <code>AdminPermission</code> objects. The key for |
| 859 | * the hashtable is the name |
| 860 | * |
| 861 | * @param permission The <code>AdminPermission</code> object to add. |
| 862 | * |
| 863 | * @exception IllegalArgumentException If the permission is not an |
| 864 | * <code>AdminPermission</code> instance. |
| 865 | * |
| 866 | * @exception SecurityException If this <code>AdminPermissionCollection</code> |
| 867 | * object has been marked read-only. |
| 868 | */ |
| 869 | public void add(Permission permission) |
| 870 | { |
| 871 | if (! (permission instanceof AdminPermission)) |
| 872 | throw new IllegalArgumentException("invalid permission: "+ |
| 873 | permission); |
| 874 | if (isReadOnly()) |
| 875 | throw new SecurityException("attempt to add a Permission to a " + |
| 876 | "readonly AdminCollection"); |
| 877 | AdminPermission ap = (AdminPermission) permission; |
| 878 | AdminPermission existing = (AdminPermission) permissions.get(ap.getName()); |
| 879 | if (existing != null){ |
| 880 | int oldMask = existing.action_mask; |
| 881 | int newMask = ap.action_mask; |
| 882 | |
| 883 | if (oldMask != newMask) { |
| 884 | permissions.put(existing.getName(), |
| 885 | new AdminPermission(existing.getName(), oldMask | newMask)); |
| 886 | } |
| 887 | } else { |
| 888 | permissions.put(ap.getName(), ap); |
| 889 | } |
| 890 | } |
| 891 | |
| 892 | |
| 893 | /** |
| 894 | * Determines if the specified permissions implies the permissions |
| 895 | * expressed in <code>permission</code>. |
| 896 | * |
| 897 | * @param permission The Permission object to compare with the <code>AdminPermission</code> |
| 898 | * objects in this collection. |
| 899 | * |
| 900 | * @return <code>true</code> if <code>permission</code> is implied by an |
| 901 | * <code>AdminPermission</code> in this collection, <code>false</code> otherwise. |
| 902 | */ |
| 903 | public boolean implies(Permission permission) |
| 904 | { |
| 905 | if (!(permission instanceof AdminPermission)) |
| 906 | return(false); |
| 907 | |
| 908 | AdminPermission target = (AdminPermission) permission; |
| 909 | |
| 910 | //just iterate one by one |
| 911 | Iterator permItr = permissions.values().iterator(); |
| 912 | |
| 913 | while(permItr.hasNext()) |
| 914 | if (((AdminPermission)permItr.next()).implies(target)) |
| 915 | return true; |
| 916 | return false; |
| 917 | } |
| 918 | |
| 919 | |
| 920 | /** |
| 921 | * Returns an enumeration of all <code>AdminPermission</code> objects in the |
| 922 | * container. |
| 923 | * |
| 924 | * @return Enumeration of all <code>AdminPermission</code> objects. |
| 925 | */ |
| 926 | |
| 927 | public Enumeration elements() |
| 928 | { |
| 929 | return(Collections.enumeration(permissions.values())); |
| 930 | } |
| 931 | } |
| 932 | } |