|
1 /* |
|
2 * Copyright 2002-2008 Sun Microsystems, Inc. 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. Sun designates this |
|
8 * particular file as subject to the "Classpath" exception as provided |
|
9 * by Sun in the LICENSE file that accompanied this code. |
|
10 * |
|
11 * This code is distributed in the hope that it will be useful, but WITHOUT |
|
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
|
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
|
14 * version 2 for more details (a copy is included in the LICENSE file that |
|
15 * accompanied this code). |
|
16 * |
|
17 * You should have received a copy of the GNU General Public License version |
|
18 * 2 along with this work; if not, write to the Free Software Foundation, |
|
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
|
20 * |
|
21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, |
|
22 * CA 95054 USA or visit www.sun.com if you need additional information or |
|
23 * have any questions. |
|
24 */ |
|
25 |
|
26 package javax.management.namespace; |
|
27 |
|
28 import javax.management.*; |
|
29 import com.sun.jmx.mbeanserver.Util; |
|
30 import java.io.IOException; |
|
31 import java.io.ObjectInputStream; |
|
32 import java.security.Permission; |
|
33 |
|
34 /** |
|
35 * <p>A permission controlling access to MBeans located in namespaces. |
|
36 * If a security manager has been set using {@link |
|
37 * System#setSecurityManager}, most operations on an MBean mounted in a |
|
38 * namespace require that the caller's permissions imply a |
|
39 * JMXNamespacePermission appropriate for the operation. |
|
40 * This is described in detail in the |
|
41 * documentation for the |
|
42 * <a href="JMXNamespace.html#PermissionChecks">JMXNamespace</a> |
|
43 * class.</p> |
|
44 * |
|
45 * <p>As with other {@link Permission} objects, |
|
46 * a JMXNamespacePermission can represent either a permission that |
|
47 * you <em>have</em> or a permission that you <em>need</em>. |
|
48 * When a sensitive operation is being checked for permission, |
|
49 * a JMXNamespacePermission is constructed |
|
50 * representing the permission you need. The operation is only |
|
51 * allowed if the permissions you have {@linkplain #implies imply} the |
|
52 * permission you need.</p> |
|
53 * |
|
54 * <p>A JMXNamespacePermission contains four items of information:</p> |
|
55 * |
|
56 * <ul> |
|
57 * |
|
58 * <li id="Action"><p>The <em>action</em>.</p> |
|
59 * <p>For a permission you need, |
|
60 * this is one of the actions in the list <a |
|
61 * href="#action-list">below</a>. For a permission you have, this is |
|
62 * a comma-separated list of those actions, or <code>*</code>, |
|
63 * representing all actions.</p> |
|
64 * |
|
65 * <p>The action is returned by {@link #getActions()}.</p> |
|
66 * |
|
67 * <li id="MBeanServerName"><p>The <em>MBean Server name</em>.</p> |
|
68 * |
|
69 * <p>For a permission you need, this is the {@linkplain |
|
70 * javax.management.MBeanServerFactory#getMBeanServerName |
|
71 * name of the MBeanServer} |
|
72 * from which the <a href="#MBeanName">MBean</a> is accessed.</p> |
|
73 * |
|
74 * <p>For a permission you have, this is either the {@linkplain |
|
75 * javax.management.MBeanServerFactory#getMBeanServerName |
|
76 * name of the MBeanServer} from which the <a href="#MBeanName">MBean</a> |
|
77 * for which you have this permission is accessed, |
|
78 * or a pattern against which that MBean Server name will be matched.<br> |
|
79 * An {@code mbeanServername} pattern can also be empty, or the single |
|
80 * character {@code "*"}, both of which match any {@code MBeanServer} name. |
|
81 * The string {@code "-"} doesn't match any MBeanServer name. |
|
82 * </p> |
|
83 * |
|
84 * <p>Example:</p> |
|
85 * <pre> |
|
86 * // grant permission to invoke the operation "stop" on any MBean |
|
87 * // whose name matches "a//**//*:type=JMXConnectorServer" when |
|
88 * // accessed from any MBeanServer whose name matches myapp.*" |
|
89 * permission javax.management.namespace.JMXNamespacePermission "myapp.*::stop[a//**//*:type=JMXConnectorServer]", "invoke"; |
|
90 * </pre> |
|
91 * |
|
92 * <li id="Member"><p>The <em>member</em>.</p> |
|
93 * |
|
94 * <p>For a permission you need, this is the name of the attribute or |
|
95 * operation you are accessing. For operations that do not reference |
|
96 * an attribute or operation, the member is null.</p> |
|
97 * |
|
98 * <p>For a permission you have, this is either the name of an attribute |
|
99 * or operation you can access, or it is empty or the single character |
|
100 * "<code>*</code>", both of which grant access to any member.</p> |
|
101 * |
|
102 * <p>There is a special case for actions {@code registerMBean} and |
|
103 * {@code instantiate}, where for a permission you need, {@code member} |
|
104 * indicates the name of the class for which you are trying |
|
105 * to create, instantiate, or register an MBean instance. For a |
|
106 * permission you have, it is a pattern that will be matched against |
|
107 * the full class name of the MBean being created, instantiated, or |
|
108 * registered. |
|
109 * </p> |
|
110 * |
|
111 * |
|
112 * <li id="MBeanName"><p>The <em>object name</em>.</p> |
|
113 * |
|
114 * <p>For a permission you need, this is the {@link ObjectName} of the |
|
115 * MBean you are accessing. It is of the form {@code <namespace>//<mbean name>} |
|
116 * where {@code <namespace>} is the name of the name space for which the |
|
117 * permission is checked, and {@code <mbean name>} is the name of the MBean |
|
118 * within that namespace. |
|
119 * <br> |
|
120 * For operations that do not reference a |
|
121 * single MBean, the <em>object name</em> is null. It is never an object |
|
122 * name pattern. |
|
123 * </p> |
|
124 * |
|
125 * <p>For a permission you have, this is the {@link ObjectName} of the |
|
126 * MBean or MBeans you can access. It is of the form |
|
127 * {@code <namespace>//<mbean name>} |
|
128 * where {@code <namespace>} is the name of the name space for which the |
|
129 * permission is checked, and |
|
130 * {@code <mbean name>} is the name of the MBean |
|
131 * within that namespace. Both {@code <namespace>} and {@code <mbean name>} |
|
132 * can be patterns. The <em>object name</em> |
|
133 * may also be empty, which grants access to all MBeans whatever their |
|
134 * name and namespace. |
|
135 * When included in a namespace path the special path element |
|
136 * <code>**</code> matches any number of sub namespaces |
|
137 * recursively, but only if used as a complete namespace path element, |
|
138 * as in <code>**//b//c//D:k=v</code> or <code>a//**//c//D:k=v</code> |
|
139 * - see <a href="#metawildcard">below</a>. |
|
140 * </p> |
|
141 * |
|
142 * |
|
143 * </ul> |
|
144 * |
|
145 * <p>If you have a JMXNamespacePermission, it allows operations only |
|
146 * if all four of the items match.</p> |
|
147 * |
|
148 * <p>The <a href="#MBeanServerName">MBeanServer name</a>, |
|
149 * <a href="#Member">member</a>, and <a href="#MBeanName">object name</a> |
|
150 * can be written together |
|
151 * as a single string, which is the <em>name</em> of this permission. |
|
152 * The name of the permission is the string returned by {@link |
|
153 * java.security.Permission#getName() getName()}. |
|
154 * The format of the string is:</p> |
|
155 * |
|
156 * <blockquote> |
|
157 * {@code <mbean server name>::<member>[<namespace>//<mbean name>]} |
|
158 * </blockquote> |
|
159 * |
|
160 * <p> |
|
161 * The {@code <mbean server name>} is optional. If omitted, {@code "*"} is |
|
162 * assumed, and these three permission names |
|
163 * are thus equivalent: |
|
164 * </p> |
|
165 * <blockquote> |
|
166 * {@code *::<member>[<namespace>//<mbean name>]}<br> |
|
167 * {@code ::<member>[<namespace>//<mbean name>]}<br> |
|
168 * {@code <member>[<namespace>//<mbean name>]}<br> |
|
169 * </blockquote> |
|
170 * <p> |
|
171 * The {@code <namespace>//<mbean name>} string can be in the form |
|
172 * of a traditional ObjectName |
|
173 * pattern - meaning that <code>?</code> will match any single |
|
174 * character, and <code>*</code> will match any sequence of characters, |
|
175 * except {@value |
|
176 * javax.management.namespace.JMXNamespaces#NAMESPACE_SEPARATOR} |
|
177 * In addition, when included in a namespace path the special |
|
178 * path element <code>**</code> matches any number of sub namespaces |
|
179 * recursively. |
|
180 * A {@code <namespace>//<mbean name>} string of the form |
|
181 * <code>**//*:*</code> thus means that the permission is |
|
182 * granted for all MBeans in all namespaces, recursively (see |
|
183 * <a href="#metawildcard">below</a> for more details. |
|
184 * </p> |
|
185 * <p>Namespace permission checking may be tricky to configure, depending |
|
186 * on whether the namespaces crossed to reach the MBean are local or |
|
187 * remote.<br> |
|
188 * For instance, let <code>a//b//D:k=v</code> be an MBean exposing an |
|
189 * attribute <code>Foo</code>. |
|
190 * If namespace <code>a</code> is a plain JMXNamespace pointing to |
|
191 * a local MBeanServer in the same JVM, then the permissions you need |
|
192 * to get the attribute <code>Foo</code> will be: |
|
193 * </p> |
|
194 * <pre> |
|
195 * // granting permission to access attribute 'Foo' of MBean a//b//D:k=v |
|
196 * // from MBeanServer named 'srv1' |
|
197 * // This permission will be checked by the MBeanServer that contains 'a'. |
|
198 * srv1::Foo[a//b//D:k=v] |
|
199 * |
|
200 * // Since a is local, you also need the following additional permission, |
|
201 * // which will be checked by the MBeanServer 'srv2' that contains 'b': |
|
202 * // |
|
203 * // granting permission to access attribute 'Foo' of MBean b//D:k=v from |
|
204 * // 'srv2' |
|
205 * srv2::Foo[b//D:k=v] |
|
206 * </pre> |
|
207 * <p>On the other hand, if namespace <code>a</code> is a JMXRemoteNamespace |
|
208 * pointing to an MBeanServer in a remote JVM, then the only permission you |
|
209 * need to get the attribute <code>Foo</code> will be: |
|
210 * </p> |
|
211 * <pre> |
|
212 * // granting permission to access attribute 'Foo' of MBean a//b//D:k=v |
|
213 * // from 'srv1' |
|
214 * srv1::Foo[a//b//D:k=v] |
|
215 * </pre> |
|
216 * <p>The namespace <code>b</code> resides in the remote JVM, and |
|
217 * therefore the permissions concerning access to MBeans from |
|
218 * namespace 'b' will only be checked in the remote JVM, if that JVM is |
|
219 * configured to do so. |
|
220 * </p> |
|
221 * |
|
222 * <p>The {@code <mbean name>} is written using the usual syntax for {@link |
|
223 * ObjectName}. It may contain any legal characters, including |
|
224 * <code>]</code>. It is terminated by a <code>]</code> character |
|
225 * that is the last character in the string. |
|
226 * </p> |
|
227 * <p>Below are some examples of permission names:</p> |
|
228 * <pre> |
|
229 * // allows access to Foo in 'a//b//*:*' from any MBeanServer in the JVM. |
|
230 * Foo[a//b//*:*] |
|
231 * |
|
232 * // allows access to Foo in all subnamespaces of 'a//b', but only for |
|
233 * // MBeanServers whose name matches 'myapp.*' |
|
234 * myapp.*::Foo[a//b//**//*:*] |
|
235 * |
|
236 * // allows access to Foo from all namespaces in the MBeanServer named |
|
237 * // 'myapp.srv1' - but not recursively. |
|
238 * myapp.srv1::Foo[*//*:*] |
|
239 * </pre> |
|
240 * <p>For instance, the first two permissions listed above |
|
241 * will let through {@code getAttribute("a//b//D:k=v","Foo");} in |
|
242 * all MBeanServers, but will block access to |
|
243 * {@code getAttribute("a//b//c//D:k=v","Foo");} in MBeanServers whose |
|
244 * name do not start with {@code "myapp."}. |
|
245 * </p> |
|
246 * <p><a name="metawildcard">Depending on how your namespace hierarchy |
|
247 * is defined some of these wildcard permission names can be useful</a>:</p> |
|
248 * <pre> |
|
249 * // allows access to Foo in all namespaces, recursively. |
|
250 * // |
|
251 * *::Foo[**//*:*] |
|
252 * |
|
253 * // This permission name is the equivalent to the permission names above: |
|
254 * // Foo[**//*:*] and Foo[] are equivalent. |
|
255 * // |
|
256 * Foo[] |
|
257 * |
|
258 * // This permission name is the equivalent to the two permission names |
|
259 * // above: |
|
260 * // Foo[**//*:*], Foo[], Foo are equivalent. |
|
261 * // |
|
262 * Foo |
|
263 * |
|
264 * // allows access to Foo from all namespaces - but not recursively. |
|
265 * // This wildcard permission complements the previous one: it allows |
|
266 * // access to 'Foo' from an MBean directly registered in any local namespace. |
|
267 * // |
|
268 * Foo[*//*:*] |
|
269 * |
|
270 * </pre> |
|
271 * <p><b>Note on wildcards:</b> In an object name pattern, a path element |
|
272 * of exactly <code>**</code> corresponds to a meta |
|
273 * wildcard that will match any number of sub namespaces. Hence:</p> |
|
274 * <ul> |
|
275 * <table border="1"> |
|
276 * <thead><th>pattern</th><th>matches</th><th>doesn't match</th></thead> |
|
277 * <tbody> |
|
278 * <tr><td><code>**//D:k=v</code></td> |
|
279 * <td><code>a//D:k=v</code><br> |
|
280 * <code>a//b//D:k=v</code><br> |
|
281 * <code>a//b//c//D:k=v</code></td> |
|
282 * <td><code>D:k=v</code></td></tr> |
|
283 * <tr><td><code>a//**//D:k=v</code></td> |
|
284 * <td><code>a//b//D:k=v</code><br> |
|
285 * <code>a//b//c//D:k=v</code></td> |
|
286 * <td><code>b//b//c//D:k=v</code><br> |
|
287 * <code>a//D:k=v</code><br> |
|
288 * <code>D:k=v</code></td></tr> |
|
289 * <tr><td><code>a//**//e//D:k=v</code></td> |
|
290 * <td><code>a//b//e//D:k=v</code><br> |
|
291 * <code>a//b//c//e//D:k=v</code></td> |
|
292 * <td><code>a//b//c//c//D:k=v</code><br> |
|
293 * <code>b//b//c//e//D:k=v</code><br> |
|
294 * <code>a//e//D:k=v</code><br> |
|
295 * <code>e//D:k=v</code></td></tr> |
|
296 * <tr><td><code>a//b**//e//D:k=v</code></td> |
|
297 * <td><code>a//b//e//D:k=v</code></td> |
|
298 * <td><code>a//b//c//e//D:k=v</code><br> |
|
299 * because in that case <code>b**</code><br> |
|
300 * is not a meta-wildcard - and <code>b**</code><br> |
|
301 * is thus equivalent to <code>b*</code>.</td></tr> |
|
302 * </tbody> |
|
303 * </table> |
|
304 *</ul> |
|
305 * |
|
306 * <p>If {@code <mbean server name>::} is omitted, then one of |
|
307 * <code>member</code> or <code>object name</code> may be omitted. |
|
308 * If the <code>object name</code> is omitted, |
|
309 * the <code>[]</code> may be too (but does not have to be). It is |
|
310 * not legal to omit all items, that is to have a <em>name</em> |
|
311 * which is the empty string.</p> |
|
312 * <p>If {@code <mbean server name>} is present, it <b>must be followed</b> by |
|
313 * the {@code "::"} separator - otherwise it will be interpreted as |
|
314 * a {@code member name}. |
|
315 * </p> |
|
316 * |
|
317 * <p> |
|
318 * One or more of the <a href="#MBeanServerName">MBean Server name</a>, |
|
319 * <a href="#Member">member</a> |
|
320 * or <a href="#MBeanName">object name</a> may be the character "<code>-</code>", |
|
321 * which is equivalent to a null value. A null value is implied by |
|
322 * any value (including another null value) but does not imply any |
|
323 * other value. |
|
324 * </p> |
|
325 * |
|
326 * <p><a name="action-list">The possible actions are these:</a></p> |
|
327 * |
|
328 * <ul> |
|
329 * <li>addNotificationListener</li> |
|
330 * <li>getAttribute</li> |
|
331 * <li>getClassLoader</li> |
|
332 * <li>getClassLoaderFor</li> |
|
333 * <li>getClassLoaderRepository</li> |
|
334 * <li>getMBeanInfo</li> |
|
335 * <li>getObjectInstance</li> |
|
336 * <li>instantiate</li> |
|
337 * <li>invoke</li> |
|
338 * <li>isInstanceOf</li> |
|
339 * <li>queryMBeans</li> |
|
340 * <li>queryNames</li> |
|
341 * <li>registerMBean</li> |
|
342 * <li>removeNotificationListener</li> |
|
343 * <li>setAttribute</li> |
|
344 * <li>unregisterMBean</li> |
|
345 * </ul> |
|
346 * |
|
347 * <p>In a comma-separated list of actions, spaces are allowed before |
|
348 * and after each action.</p> |
|
349 * |
|
350 * @since 1.7 |
|
351 */ |
|
352 public class JMXNamespacePermission extends Permission { |
|
353 |
|
354 private static final long serialVersionUID = -2416928705275160661L; |
|
355 |
|
356 private static final String WILDPATH = "**" + |
|
357 JMXNamespaces.NAMESPACE_SEPARATOR + "*"; |
|
358 |
|
359 /** |
|
360 * Actions list. |
|
361 */ |
|
362 private static final int AddNotificationListener = 0x00001; |
|
363 private static final int GetAttribute = 0x00002; |
|
364 private static final int GetClassLoader = 0x00004; |
|
365 private static final int GetClassLoaderFor = 0x00008; |
|
366 private static final int GetClassLoaderRepository = 0x00010; |
|
367 // No GetDomains because it is not possible to route a call to |
|
368 // getDomains() on a NamespaceInterceptor - getDomains() doesn't |
|
369 // have any ObjectName. |
|
370 // private static final int GetDomains = 0x00020; |
|
371 private static final int GetMBeanInfo = 0x00040; |
|
372 private static final int GetObjectInstance = 0x00080; |
|
373 private static final int Instantiate = 0x00100; |
|
374 private static final int Invoke = 0x00200; |
|
375 private static final int IsInstanceOf = 0x00400; |
|
376 private static final int QueryMBeans = 0x00800; |
|
377 private static final int QueryNames = 0x01000; |
|
378 private static final int RegisterMBean = 0x02000; |
|
379 private static final int RemoveNotificationListener = 0x04000; |
|
380 private static final int SetAttribute = 0x08000; |
|
381 private static final int UnregisterMBean = 0x10000; |
|
382 |
|
383 /** |
|
384 * No actions. |
|
385 */ |
|
386 private static final int NONE = 0x00000; |
|
387 |
|
388 /** |
|
389 * All actions. |
|
390 */ |
|
391 // No GetDomains because it is not possible to route a call to |
|
392 // getDomains() on a NamespaceInterceptor - getDomains() doesn't |
|
393 // have any ObjectName. |
|
394 // |
|
395 private static final int ALL = |
|
396 AddNotificationListener | |
|
397 GetAttribute | |
|
398 GetClassLoader | |
|
399 GetClassLoaderFor | |
|
400 GetClassLoaderRepository | |
|
401 GetMBeanInfo | |
|
402 GetObjectInstance | |
|
403 Instantiate | |
|
404 Invoke | |
|
405 IsInstanceOf | |
|
406 QueryMBeans | |
|
407 QueryNames | |
|
408 RegisterMBean | |
|
409 RemoveNotificationListener | |
|
410 SetAttribute | |
|
411 UnregisterMBean; |
|
412 |
|
413 /** |
|
414 * The actions string. |
|
415 */ |
|
416 private String actions; |
|
417 |
|
418 /** |
|
419 * The actions mask. |
|
420 */ |
|
421 private transient int mask; |
|
422 |
|
423 /** |
|
424 * The name of the MBeanServer in which this permission is checked, or |
|
425 * granted. If null, is implied by any MBean server name |
|
426 * but does not imply any non-null MBean server name. |
|
427 */ |
|
428 private transient String mbeanServerName; |
|
429 |
|
430 /** |
|
431 * The member that must match. If null, is implied by any member |
|
432 * but does not imply any non-null member. |
|
433 */ |
|
434 private transient String member; |
|
435 |
|
436 /** |
|
437 * The objectName that must match. If null, is implied by any |
|
438 * objectName but does not imply any non-null objectName. |
|
439 */ |
|
440 private transient ObjectName objectName; |
|
441 |
|
442 /** |
|
443 * If objectName is missing from name, then allnames will be |
|
444 * set to true. |
|
445 */ |
|
446 private transient boolean allnames = false; |
|
447 |
|
448 /** |
|
449 * Parse <code>actions</code> parameter. |
|
450 */ |
|
451 private void parseActions() { |
|
452 |
|
453 int amask; |
|
454 |
|
455 if (actions == null) |
|
456 throw new IllegalArgumentException("JMXNamespaceAccessPermission: " + |
|
457 "actions can't be null"); |
|
458 if (actions.equals("")) |
|
459 throw new IllegalArgumentException("JMXNamespaceAccessPermission: " + |
|
460 "actions can't be empty"); |
|
461 |
|
462 amask = getMask(actions); |
|
463 |
|
464 if ((amask & ALL) != amask) |
|
465 throw new IllegalArgumentException("Invalid actions mask"); |
|
466 if (amask == NONE) |
|
467 throw new IllegalArgumentException("Invalid actions mask"); |
|
468 this.mask = amask; |
|
469 } |
|
470 |
|
471 /** |
|
472 * Parse <code>name</code> parameter. |
|
473 */ |
|
474 private void parseName() { |
|
475 String name = getName(); |
|
476 |
|
477 if (name == null) |
|
478 throw new IllegalArgumentException("JMXNamespaceAccessPermission name " + |
|
479 "cannot be null"); |
|
480 |
|
481 if (name.equals("")) |
|
482 throw new IllegalArgumentException("JMXNamespaceAccessPermission name " + |
|
483 "cannot be empty"); |
|
484 final int sepIndex = name.indexOf("::"); |
|
485 if (sepIndex < 0) { |
|
486 setMBeanServerName("*"); |
|
487 } else { |
|
488 setMBeanServerName(name.substring(0,sepIndex)); |
|
489 } |
|
490 |
|
491 /* The name looks like "mbeanServerName::member[objectname]". |
|
492 We subtract elements from the right as we parse, so after |
|
493 parsing the objectname we have "class#member" and after parsing the |
|
494 member we have "class". Each element is optional. */ |
|
495 |
|
496 // Parse ObjectName |
|
497 |
|
498 final int start = (sepIndex<0)?0:sepIndex+2; |
|
499 int openingBracket = name.indexOf("[",start); |
|
500 if (openingBracket == -1) { |
|
501 // If "[on]" missing then ObjectName("*:*") |
|
502 // |
|
503 objectName = null; |
|
504 allnames = true; |
|
505 openingBracket=name.length(); |
|
506 } else { |
|
507 if (!name.endsWith("]")) { |
|
508 throw new IllegalArgumentException("JMXNamespaceAccessPermission: " + |
|
509 "The ObjectName in the " + |
|
510 "target name must be " + |
|
511 "included in square " + |
|
512 "brackets"); |
|
513 } else { |
|
514 // Create ObjectName |
|
515 // |
|
516 String on = name.substring(openingBracket + 1, |
|
517 name.length() - 1); |
|
518 try { |
|
519 // If "[]" then allnames are implied |
|
520 // |
|
521 final ObjectName target; |
|
522 final boolean all; |
|
523 if (on.equals("")) { |
|
524 target = null; |
|
525 all = true; |
|
526 } else if (on.equals("-")) { |
|
527 target = null; |
|
528 all = false; |
|
529 } else { |
|
530 target = new ObjectName(on); |
|
531 all = false; |
|
532 } |
|
533 setObjectName(target,all); |
|
534 } catch (MalformedObjectNameException e) { |
|
535 throw new IllegalArgumentException( |
|
536 "JMXNamespaceAccessPermission: " + |
|
537 "The target name does " + |
|
538 "not specify a valid " + |
|
539 "ObjectName", e); |
|
540 } |
|
541 } |
|
542 } |
|
543 |
|
544 final String memberName = name.substring(start,openingBracket); |
|
545 setMember(memberName); |
|
546 } |
|
547 |
|
548 private void setObjectName(ObjectName target, boolean all) { |
|
549 if (target != null && |
|
550 !Util.wildpathmatch(target.getDomain(), WILDPATH)) { |
|
551 throw new IllegalArgumentException( |
|
552 "The target name does not contain " + |
|
553 "any namespace: "+String.valueOf(target)); |
|
554 } else if (target != null) { |
|
555 final String domain = target.getDomain(); |
|
556 final int seplen = JMXNamespaces.NAMESPACE_SEPARATOR.length(); |
|
557 final int sepc = domain.indexOf(JMXNamespaces.NAMESPACE_SEPARATOR); |
|
558 if (sepc < 0 || (sepc+seplen)==domain.length()) { |
|
559 throw new IllegalArgumentException(String.valueOf(target)+ |
|
560 ": no namespace in domain"); |
|
561 } |
|
562 } |
|
563 objectName = target; |
|
564 allnames = all; |
|
565 } |
|
566 |
|
567 /** |
|
568 * Assign fields based on className, member, and objectName |
|
569 * parameters. |
|
570 */ |
|
571 // private void initName(String namespaceName, String member, |
|
572 // ObjectName objectName, boolean allnames) { |
|
573 // setNamespace(namespaceName); |
|
574 private void initName(String mbeanServerName, String member, |
|
575 ObjectName mbeanName, boolean all) { |
|
576 setMBeanServerName(mbeanServerName); |
|
577 setMember(member); |
|
578 setObjectName(mbeanName, all); |
|
579 } |
|
580 |
|
581 private void setMBeanServerName(String mbeanServerName) { |
|
582 if (mbeanServerName == null || mbeanServerName.equals("-")) { |
|
583 this.mbeanServerName = null; |
|
584 } else if (mbeanServerName.equals("")) { |
|
585 this.mbeanServerName = "*"; |
|
586 } else { |
|
587 this.mbeanServerName = mbeanServerName; |
|
588 } |
|
589 } |
|
590 |
|
591 private void setMember(String member) { |
|
592 if (member == null || member.equals("-")) |
|
593 this.member = null; |
|
594 else if (member.equals("")) |
|
595 this.member = "*"; |
|
596 else |
|
597 this.member = member; |
|
598 } |
|
599 |
|
600 /** |
|
601 * <p>Create a new JMXNamespacePermission object with the |
|
602 * specified target name and actions.</p> |
|
603 * |
|
604 * <p>The target name is of the form |
|
605 * "<code>mbeanServerName::member[objectName]</code>" where each part is |
|
606 * optional. This target name must not be empty or null. |
|
607 * If <code>objectName</code> is present, it is of |
|
608 * the form <code>namespace//MBeanName</code>. |
|
609 * </p> |
|
610 * <p> |
|
611 * For a permission you need, {@code mbeanServerName} is the |
|
612 * <a href="#MBeanServerName">name of the MBeanServer</a> from |
|
613 * which {@code objectName} is being accessed. |
|
614 * </p> |
|
615 * <p> |
|
616 * For a permission you have, {@code mbeanServerName} is the |
|
617 * <a href="#MBeanServerName">name of the MBeanServer</a> from |
|
618 * which access to {@code objectName} is granted. |
|
619 * It can also be a pattern, and if omitted, {@code "*"} is assumed, |
|
620 * meaning that access to {@code objectName} is granted in all |
|
621 * MBean servers in the JVM. |
|
622 * </p> |
|
623 * |
|
624 * <p>The actions parameter contains a comma-separated list of the |
|
625 * desired actions granted on the target name. It must not be |
|
626 * empty or null.</p> |
|
627 * |
|
628 * @param name the triplet "mbeanServerName::member[objectName]". |
|
629 * If <code>objectName</code> is present, it is of |
|
630 * the form <code>namespace//MBeanName</code>. |
|
631 * @param actions the action string. |
|
632 * |
|
633 * @exception IllegalArgumentException if the <code>name</code> or |
|
634 * <code>actions</code> is invalid. |
|
635 */ |
|
636 public JMXNamespacePermission(String name, String actions) { |
|
637 super(name); |
|
638 |
|
639 parseName(); |
|
640 |
|
641 this.actions = actions; |
|
642 parseActions(); |
|
643 } |
|
644 |
|
645 /** |
|
646 * <p>Create a new JMXNamespacePermission object with the specified |
|
647 * target name (namespace name, member, object name) and actions.</p> |
|
648 * |
|
649 * <p>The {@code MBeanServer} name, member and object name |
|
650 * parameters define a target name of the form |
|
651 * "<code>mbeanServerName::member[objectName]</code>" where each |
|
652 * part is optional. This will be the result of {@link #getName()} on the |
|
653 * resultant JMXNamespacePermission. |
|
654 * If the <code>mbeanServerName</code> is empty or exactly {@code "*"}, then |
|
655 * "{@code mbeanServerName::}" is omitted in that result. |
|
656 * </p> |
|
657 * |
|
658 * <p>The actions parameter contains a comma-separated list of the |
|
659 * desired actions granted on the target name. It must not be |
|
660 * empty or null.</p> |
|
661 * |
|
662 * @param mbeanServerName the name of the {@code MBeanServer} to which this |
|
663 * permission applies. |
|
664 * May be null or <code>"-"</code>, which represents an MBeanServer name |
|
665 * that is implied by any MBeanServer name but does not imply any other |
|
666 * MBeanServer name. |
|
667 * @param member the member to which this permission applies. May |
|
668 * be null or <code>"-"</code>, which represents a member that is |
|
669 * implied by any member but does not imply any other member. |
|
670 * @param objectName the object name to which this permission |
|
671 * applies. |
|
672 * May be null, which represents an object name that is |
|
673 * implied by any object name but does not imply any other object |
|
674 * name. If not null, the {@code objectName} must be of the |
|
675 * form {@code <namespace>//<mbean name>} - where {@code <namespace>} |
|
676 * can be a domain pattern, and {@code <mbean name>} can be an ObjectName |
|
677 * pattern. |
|
678 * For a permission you need, {@code <namespace>} is the name of the |
|
679 * name space for which the permission is checked, and {@code <mbean name>} |
|
680 * is the name of the MBean in that namespace. |
|
681 * The composed name {@code <namespace>//<mbean name>} thus represents the |
|
682 * name of the MBean as seen by the {@code mbeanServerName} containing |
|
683 * {@code <namespace>}. |
|
684 * |
|
685 * @param actions the action string. |
|
686 */ |
|
687 public JMXNamespacePermission( |
|
688 String mbeanServerName, |
|
689 String member, |
|
690 ObjectName objectName, |
|
691 String actions) { |
|
692 this(mbeanServerName, member, objectName, false, actions); |
|
693 // this(member, objectName, false, actions); |
|
694 } |
|
695 |
|
696 /** |
|
697 * <p>Create a new JMXNamespacePermission object with the specified |
|
698 * MBean Server name, member, and actions.</p> |
|
699 * |
|
700 * <p>The {@code MBeanServer} name and member |
|
701 * parameters define a target name of the form |
|
702 * "<code>mbeanServerName::member[]</code>" where each |
|
703 * part is optional. This will be the result of {@link #getName()} on the |
|
704 * resultant JMXNamespacePermission. |
|
705 * If the <code>mbeanServerName</code> is empty or exactly {@code "*"}, then |
|
706 * "{@code mbeanServerName::}" is omitted in that result. |
|
707 * </p> |
|
708 * |
|
709 * <p>The actions parameter contains a comma-separated list of the |
|
710 * desired actions granted on the target name. It must not be |
|
711 * empty or null.</p> |
|
712 * |
|
713 * @param mbeanServerName the name of the {@code MBeanServer} to which this |
|
714 * permission applies. |
|
715 * May be null or <code>"-"</code>, which represents an MBeanServer name |
|
716 * that is implied by any MBeanServer name but does not imply any other |
|
717 * MBeanServer name. |
|
718 * @param member the member to which this permission applies. May |
|
719 * be null or <code>"-"</code>, which represents a member that is |
|
720 * implied by any member but does not imply any other member. |
|
721 * @param actions the action string. |
|
722 */ |
|
723 public JMXNamespacePermission(String mbeanServerName, |
|
724 String member, |
|
725 String actions) { |
|
726 this(mbeanServerName,member,null,true,actions); |
|
727 // this(member,null,allnames,actions); |
|
728 } |
|
729 |
|
730 /** |
|
731 * <p>Create a new JMXNamespacePermission object with the specified |
|
732 * target name (namespace name, member, object name) and actions.</p> |
|
733 * |
|
734 * <p>The MBean Server name, member and object name parameters define a |
|
735 * target name of the form |
|
736 * "<code>mbeanServerName::member[objectName]</code>" where each part is |
|
737 * optional. This will be the result of {@link |
|
738 * java.security.Permission#getName() getName()} on the |
|
739 * resultant JMXNamespacePermission.</p> |
|
740 * |
|
741 * <p>The actions parameter contains a comma-separated list of the |
|
742 * desired actions granted on the target name. It must not be |
|
743 * empty or null.</p> |
|
744 * |
|
745 * @param mbeanServerName the name of the {@code MBeanServer} to which this |
|
746 * permission applies. |
|
747 * May be null or <code>"-"</code>, which represents an MBeanServer name |
|
748 * that is implied by any MBeanServer name but does not imply any other |
|
749 * MBeanServer name. |
|
750 * @param member the member to which this permission applies. May |
|
751 * be null or <code>"-"</code>, which represents a member that is |
|
752 * implied by any member but does not imply any other member. |
|
753 * @param objectName the object name to which this permission |
|
754 * applies. If null, and allnames is false, represents an object |
|
755 * name that is implied by any object name but does not imply any |
|
756 * other object name. Otherwise, if allnames is true, it represents |
|
757 * a meta wildcard that matches all object names. It is equivalent to |
|
758 * a missing objectName ("[]") in the {@link |
|
759 * java.security.Permission#getName() name} property. |
|
760 * @param allnames represent a meta wildcard indicating that the |
|
761 * objectName was not specified. This implies all objectnames |
|
762 * that match "*:*" and all object names that match |
|
763 * "**//*:*" |
|
764 * @param actions the action string. |
|
765 */ |
|
766 private JMXNamespacePermission(String mbeanServerName, |
|
767 String member, |
|
768 ObjectName objectName, |
|
769 boolean allnames, |
|
770 String actions) { |
|
771 |
|
772 super(makeName(mbeanServerName, |
|
773 member, objectName, allnames)); |
|
774 initName(mbeanServerName, |
|
775 member, objectName, allnames); |
|
776 |
|
777 this.actions = actions; |
|
778 parseActions(); |
|
779 } |
|
780 |
|
781 private static String makeName(String mbeanServerName, |
|
782 String memberName, ObjectName objName, boolean allMBeans) { |
|
783 final StringBuilder name = new StringBuilder(); |
|
784 if (mbeanServerName == null) |
|
785 mbeanServerName = "-"; |
|
786 if (!mbeanServerName.equals("") && !mbeanServerName.equals("*")) |
|
787 name.append(mbeanServerName).append("::"); |
|
788 if (memberName == null) |
|
789 memberName = "-"; |
|
790 name.append(memberName); |
|
791 if (objName == null) { |
|
792 if (allMBeans) |
|
793 name.append("[]"); |
|
794 else |
|
795 name.append("[-]"); |
|
796 } else { |
|
797 final String domain = objName.getDomain(); |
|
798 final int seplen = JMXNamespaces.NAMESPACE_SEPARATOR.length(); |
|
799 final int sepc = domain.indexOf(JMXNamespaces.NAMESPACE_SEPARATOR); |
|
800 if (sepc < 0 || (sepc+seplen)==domain.length()) { |
|
801 throw new IllegalArgumentException(String.valueOf(objName)+ |
|
802 ": no namespace in domain"); |
|
803 } |
|
804 final String can = objName.getCanonicalName(); |
|
805 name.append("[").append(can).append("]"); |
|
806 } |
|
807 return name.toString(); |
|
808 } |
|
809 |
|
810 /** |
|
811 * Returns the "canonical string representation" of the actions. That is, |
|
812 * this method always returns actions in alphabetical order. |
|
813 * |
|
814 * @return the canonical string representation of the actions. |
|
815 */ |
|
816 public String getActions() { |
|
817 |
|
818 if (actions == null) |
|
819 actions = getActions(this.mask); |
|
820 |
|
821 return actions; |
|
822 } |
|
823 |
|
824 /** |
|
825 * Returns the "canonical string representation" |
|
826 * of the actions from the mask. |
|
827 */ |
|
828 private static String getActions(int mask) { |
|
829 final StringBuilder sb = new StringBuilder(); |
|
830 boolean comma = false; |
|
831 |
|
832 if ((mask & AddNotificationListener) == AddNotificationListener) { |
|
833 comma = true; |
|
834 sb.append("addNotificationListener"); |
|
835 } |
|
836 |
|
837 if ((mask & GetAttribute) == GetAttribute) { |
|
838 if (comma) sb.append(','); |
|
839 else comma = true; |
|
840 sb.append("getAttribute"); |
|
841 } |
|
842 |
|
843 if ((mask & GetClassLoader) == GetClassLoader) { |
|
844 if (comma) sb.append(','); |
|
845 else comma = true; |
|
846 sb.append("getClassLoader"); |
|
847 } |
|
848 |
|
849 if ((mask & GetClassLoaderFor) == GetClassLoaderFor) { |
|
850 if (comma) sb.append(','); |
|
851 else comma = true; |
|
852 sb.append("getClassLoaderFor"); |
|
853 } |
|
854 |
|
855 if ((mask & GetClassLoaderRepository) == GetClassLoaderRepository) { |
|
856 if (comma) sb.append(','); |
|
857 else comma = true; |
|
858 sb.append("getClassLoaderRepository"); |
|
859 } |
|
860 |
|
861 if ((mask & GetMBeanInfo) == GetMBeanInfo) { |
|
862 if (comma) sb.append(','); |
|
863 else comma = true; |
|
864 sb.append("getMBeanInfo"); |
|
865 } |
|
866 |
|
867 if ((mask & GetObjectInstance) == GetObjectInstance) { |
|
868 if (comma) sb.append(','); |
|
869 else comma = true; |
|
870 sb.append("getObjectInstance"); |
|
871 } |
|
872 |
|
873 if ((mask & Instantiate) == Instantiate) { |
|
874 if (comma) sb.append(','); |
|
875 else comma = true; |
|
876 sb.append("instantiate"); |
|
877 } |
|
878 |
|
879 if ((mask & Invoke) == Invoke) { |
|
880 if (comma) sb.append(','); |
|
881 else comma = true; |
|
882 sb.append("invoke"); |
|
883 } |
|
884 |
|
885 if ((mask & IsInstanceOf) == IsInstanceOf) { |
|
886 if (comma) sb.append(','); |
|
887 else comma = true; |
|
888 sb.append("isInstanceOf"); |
|
889 } |
|
890 |
|
891 if ((mask & QueryMBeans) == QueryMBeans) { |
|
892 if (comma) sb.append(','); |
|
893 else comma = true; |
|
894 sb.append("queryMBeans"); |
|
895 } |
|
896 |
|
897 if ((mask & QueryNames) == QueryNames) { |
|
898 if (comma) sb.append(','); |
|
899 else comma = true; |
|
900 sb.append("queryNames"); |
|
901 } |
|
902 |
|
903 if ((mask & RegisterMBean) == RegisterMBean) { |
|
904 if (comma) sb.append(','); |
|
905 else comma = true; |
|
906 sb.append("registerMBean"); |
|
907 } |
|
908 |
|
909 if ((mask & RemoveNotificationListener) == RemoveNotificationListener) { |
|
910 if (comma) sb.append(','); |
|
911 else comma = true; |
|
912 sb.append("removeNotificationListener"); |
|
913 } |
|
914 |
|
915 if ((mask & SetAttribute) == SetAttribute) { |
|
916 if (comma) sb.append(','); |
|
917 else comma = true; |
|
918 sb.append("setAttribute"); |
|
919 } |
|
920 |
|
921 if ((mask & UnregisterMBean) == UnregisterMBean) { |
|
922 if (comma) sb.append(','); |
|
923 else comma = true; |
|
924 sb.append("unregisterMBean"); |
|
925 } |
|
926 |
|
927 // No GetDomains because it is not possible to route a call to |
|
928 // getDomains() on a NamespaceInterceptor - getDomains() doesn't |
|
929 // have any ObjectName. |
|
930 |
|
931 return sb.toString(); |
|
932 } |
|
933 |
|
934 @Override |
|
935 public int hashCode() { |
|
936 return this.getName().hashCode() + this.getActions().hashCode(); |
|
937 } |
|
938 |
|
939 /** |
|
940 * Converts an action String to an integer action mask. |
|
941 * |
|
942 * @param action the action string. |
|
943 * @return the action mask. |
|
944 */ |
|
945 private static int getMask(String action) { |
|
946 |
|
947 /* |
|
948 * BE CAREFUL HERE! PARSING ORDER IS IMPORTANT IN THIS ALGORITHM. |
|
949 * |
|
950 * The 'string length' test must be performed for the lengthiest |
|
951 * strings first. |
|
952 * |
|
953 * In this permission if the "unregisterMBean" string length test is |
|
954 * performed after the "registerMBean" string length test the algorithm |
|
955 * considers the 'unregisterMBean' action as being the 'registerMBean' |
|
956 * action and a parsing error is returned. |
|
957 */ |
|
958 |
|
959 int mask = NONE; |
|
960 |
|
961 if (action == null) { |
|
962 return mask; |
|
963 } |
|
964 |
|
965 if (action.equals("*")) { |
|
966 return ALL; |
|
967 } |
|
968 |
|
969 char[] a = action.toCharArray(); |
|
970 |
|
971 int i = a.length - 1; |
|
972 if (i < 0) |
|
973 return mask; |
|
974 |
|
975 while (i != -1) { |
|
976 char c; |
|
977 |
|
978 // skip whitespace |
|
979 while ((i!=-1) && ((c = a[i]) == ' ' || |
|
980 c == '\r' || |
|
981 c == '\n' || |
|
982 c == '\f' || |
|
983 c == '\t')) |
|
984 i--; |
|
985 |
|
986 // check for the known strings |
|
987 int matchlen; |
|
988 |
|
989 // No GetDomains because it is not possible to route a call to |
|
990 // getDomains() on a NamespaceInterceptor - getDomains() doesn't |
|
991 // have any ObjectName. |
|
992 |
|
993 if (i >= 25 && /* removeNotificationListener */ |
|
994 (a[i-25] == 'r') && |
|
995 (a[i-24] == 'e') && |
|
996 (a[i-23] == 'm') && |
|
997 (a[i-22] == 'o') && |
|
998 (a[i-21] == 'v') && |
|
999 (a[i-20] == 'e') && |
|
1000 (a[i-19] == 'N') && |
|
1001 (a[i-18] == 'o') && |
|
1002 (a[i-17] == 't') && |
|
1003 (a[i-16] == 'i') && |
|
1004 (a[i-15] == 'f') && |
|
1005 (a[i-14] == 'i') && |
|
1006 (a[i-13] == 'c') && |
|
1007 (a[i-12] == 'a') && |
|
1008 (a[i-11] == 't') && |
|
1009 (a[i-10] == 'i') && |
|
1010 (a[i-9] == 'o') && |
|
1011 (a[i-8] == 'n') && |
|
1012 (a[i-7] == 'L') && |
|
1013 (a[i-6] == 'i') && |
|
1014 (a[i-5] == 's') && |
|
1015 (a[i-4] == 't') && |
|
1016 (a[i-3] == 'e') && |
|
1017 (a[i-2] == 'n') && |
|
1018 (a[i-1] == 'e') && |
|
1019 (a[i] == 'r')) { |
|
1020 matchlen = 26; |
|
1021 mask |= RemoveNotificationListener; |
|
1022 } else if (i >= 23 && /* getClassLoaderRepository */ |
|
1023 (a[i-23] == 'g') && |
|
1024 (a[i-22] == 'e') && |
|
1025 (a[i-21] == 't') && |
|
1026 (a[i-20] == 'C') && |
|
1027 (a[i-19] == 'l') && |
|
1028 (a[i-18] == 'a') && |
|
1029 (a[i-17] == 's') && |
|
1030 (a[i-16] == 's') && |
|
1031 (a[i-15] == 'L') && |
|
1032 (a[i-14] == 'o') && |
|
1033 (a[i-13] == 'a') && |
|
1034 (a[i-12] == 'd') && |
|
1035 (a[i-11] == 'e') && |
|
1036 (a[i-10] == 'r') && |
|
1037 (a[i-9] == 'R') && |
|
1038 (a[i-8] == 'e') && |
|
1039 (a[i-7] == 'p') && |
|
1040 (a[i-6] == 'o') && |
|
1041 (a[i-5] == 's') && |
|
1042 (a[i-4] == 'i') && |
|
1043 (a[i-3] == 't') && |
|
1044 (a[i-2] == 'o') && |
|
1045 (a[i-1] == 'r') && |
|
1046 (a[i] == 'y')) { |
|
1047 matchlen = 24; |
|
1048 mask |= GetClassLoaderRepository; |
|
1049 } else if (i >= 22 && /* addNotificationListener */ |
|
1050 (a[i-22] == 'a') && |
|
1051 (a[i-21] == 'd') && |
|
1052 (a[i-20] == 'd') && |
|
1053 (a[i-19] == 'N') && |
|
1054 (a[i-18] == 'o') && |
|
1055 (a[i-17] == 't') && |
|
1056 (a[i-16] == 'i') && |
|
1057 (a[i-15] == 'f') && |
|
1058 (a[i-14] == 'i') && |
|
1059 (a[i-13] == 'c') && |
|
1060 (a[i-12] == 'a') && |
|
1061 (a[i-11] == 't') && |
|
1062 (a[i-10] == 'i') && |
|
1063 (a[i-9] == 'o') && |
|
1064 (a[i-8] == 'n') && |
|
1065 (a[i-7] == 'L') && |
|
1066 (a[i-6] == 'i') && |
|
1067 (a[i-5] == 's') && |
|
1068 (a[i-4] == 't') && |
|
1069 (a[i-3] == 'e') && |
|
1070 (a[i-2] == 'n') && |
|
1071 (a[i-1] == 'e') && |
|
1072 (a[i] == 'r')) { |
|
1073 matchlen = 23; |
|
1074 mask |= AddNotificationListener; |
|
1075 } else if (i >= 16 && /* getClassLoaderFor */ |
|
1076 (a[i-16] == 'g') && |
|
1077 (a[i-15] == 'e') && |
|
1078 (a[i-14] == 't') && |
|
1079 (a[i-13] == 'C') && |
|
1080 (a[i-12] == 'l') && |
|
1081 (a[i-11] == 'a') && |
|
1082 (a[i-10] == 's') && |
|
1083 (a[i-9] == 's') && |
|
1084 (a[i-8] == 'L') && |
|
1085 (a[i-7] == 'o') && |
|
1086 (a[i-6] == 'a') && |
|
1087 (a[i-5] == 'd') && |
|
1088 (a[i-4] == 'e') && |
|
1089 (a[i-3] == 'r') && |
|
1090 (a[i-2] == 'F') && |
|
1091 (a[i-1] == 'o') && |
|
1092 (a[i] == 'r')) { |
|
1093 matchlen = 17; |
|
1094 mask |= GetClassLoaderFor; |
|
1095 } else if (i >= 16 && /* getObjectInstance */ |
|
1096 (a[i-16] == 'g') && |
|
1097 (a[i-15] == 'e') && |
|
1098 (a[i-14] == 't') && |
|
1099 (a[i-13] == 'O') && |
|
1100 (a[i-12] == 'b') && |
|
1101 (a[i-11] == 'j') && |
|
1102 (a[i-10] == 'e') && |
|
1103 (a[i-9] == 'c') && |
|
1104 (a[i-8] == 't') && |
|
1105 (a[i-7] == 'I') && |
|
1106 (a[i-6] == 'n') && |
|
1107 (a[i-5] == 's') && |
|
1108 (a[i-4] == 't') && |
|
1109 (a[i-3] == 'a') && |
|
1110 (a[i-2] == 'n') && |
|
1111 (a[i-1] == 'c') && |
|
1112 (a[i] == 'e')) { |
|
1113 matchlen = 17; |
|
1114 mask |= GetObjectInstance; |
|
1115 } else if (i >= 14 && /* unregisterMBean */ |
|
1116 (a[i-14] == 'u') && |
|
1117 (a[i-13] == 'n') && |
|
1118 (a[i-12] == 'r') && |
|
1119 (a[i-11] == 'e') && |
|
1120 (a[i-10] == 'g') && |
|
1121 (a[i-9] == 'i') && |
|
1122 (a[i-8] == 's') && |
|
1123 (a[i-7] == 't') && |
|
1124 (a[i-6] == 'e') && |
|
1125 (a[i-5] == 'r') && |
|
1126 (a[i-4] == 'M') && |
|
1127 (a[i-3] == 'B') && |
|
1128 (a[i-2] == 'e') && |
|
1129 (a[i-1] == 'a') && |
|
1130 (a[i] == 'n')) { |
|
1131 matchlen = 15; |
|
1132 mask |= UnregisterMBean; |
|
1133 } else if (i >= 13 && /* getClassLoader */ |
|
1134 (a[i-13] == 'g') && |
|
1135 (a[i-12] == 'e') && |
|
1136 (a[i-11] == 't') && |
|
1137 (a[i-10] == 'C') && |
|
1138 (a[i-9] == 'l') && |
|
1139 (a[i-8] == 'a') && |
|
1140 (a[i-7] == 's') && |
|
1141 (a[i-6] == 's') && |
|
1142 (a[i-5] == 'L') && |
|
1143 (a[i-4] == 'o') && |
|
1144 (a[i-3] == 'a') && |
|
1145 (a[i-2] == 'd') && |
|
1146 (a[i-1] == 'e') && |
|
1147 (a[i] == 'r')) { |
|
1148 matchlen = 14; |
|
1149 mask |= GetClassLoader; |
|
1150 } else if (i >= 12 && /* registerMBean */ |
|
1151 (a[i-12] == 'r') && |
|
1152 (a[i-11] == 'e') && |
|
1153 (a[i-10] == 'g') && |
|
1154 (a[i-9] == 'i') && |
|
1155 (a[i-8] == 's') && |
|
1156 (a[i-7] == 't') && |
|
1157 (a[i-6] == 'e') && |
|
1158 (a[i-5] == 'r') && |
|
1159 (a[i-4] == 'M') && |
|
1160 (a[i-3] == 'B') && |
|
1161 (a[i-2] == 'e') && |
|
1162 (a[i-1] == 'a') && |
|
1163 (a[i] == 'n')) { |
|
1164 matchlen = 13; |
|
1165 mask |= RegisterMBean; |
|
1166 } else if (i >= 11 && /* getAttribute */ |
|
1167 (a[i-11] == 'g') && |
|
1168 (a[i-10] == 'e') && |
|
1169 (a[i-9] == 't') && |
|
1170 (a[i-8] == 'A') && |
|
1171 (a[i-7] == 't') && |
|
1172 (a[i-6] == 't') && |
|
1173 (a[i-5] == 'r') && |
|
1174 (a[i-4] == 'i') && |
|
1175 (a[i-3] == 'b') && |
|
1176 (a[i-2] == 'u') && |
|
1177 (a[i-1] == 't') && |
|
1178 (a[i] == 'e')) { |
|
1179 matchlen = 12; |
|
1180 mask |= GetAttribute; |
|
1181 } else if (i >= 11 && /* getMBeanInfo */ |
|
1182 (a[i-11] == 'g') && |
|
1183 (a[i-10] == 'e') && |
|
1184 (a[i-9] == 't') && |
|
1185 (a[i-8] == 'M') && |
|
1186 (a[i-7] == 'B') && |
|
1187 (a[i-6] == 'e') && |
|
1188 (a[i-5] == 'a') && |
|
1189 (a[i-4] == 'n') && |
|
1190 (a[i-3] == 'I') && |
|
1191 (a[i-2] == 'n') && |
|
1192 (a[i-1] == 'f') && |
|
1193 (a[i] == 'o')) { |
|
1194 matchlen = 12; |
|
1195 mask |= GetMBeanInfo; |
|
1196 } else if (i >= 11 && /* isInstanceOf */ |
|
1197 (a[i-11] == 'i') && |
|
1198 (a[i-10] == 's') && |
|
1199 (a[i-9] == 'I') && |
|
1200 (a[i-8] == 'n') && |
|
1201 (a[i-7] == 's') && |
|
1202 (a[i-6] == 't') && |
|
1203 (a[i-5] == 'a') && |
|
1204 (a[i-4] == 'n') && |
|
1205 (a[i-3] == 'c') && |
|
1206 (a[i-2] == 'e') && |
|
1207 (a[i-1] == 'O') && |
|
1208 (a[i] == 'f')) { |
|
1209 matchlen = 12; |
|
1210 mask |= IsInstanceOf; |
|
1211 } else if (i >= 11 && /* setAttribute */ |
|
1212 (a[i-11] == 's') && |
|
1213 (a[i-10] == 'e') && |
|
1214 (a[i-9] == 't') && |
|
1215 (a[i-8] == 'A') && |
|
1216 (a[i-7] == 't') && |
|
1217 (a[i-6] == 't') && |
|
1218 (a[i-5] == 'r') && |
|
1219 (a[i-4] == 'i') && |
|
1220 (a[i-3] == 'b') && |
|
1221 (a[i-2] == 'u') && |
|
1222 (a[i-1] == 't') && |
|
1223 (a[i] == 'e')) { |
|
1224 matchlen = 12; |
|
1225 mask |= SetAttribute; |
|
1226 } else if (i >= 10 && /* instantiate */ |
|
1227 (a[i-10] == 'i') && |
|
1228 (a[i-9] == 'n') && |
|
1229 (a[i-8] == 's') && |
|
1230 (a[i-7] == 't') && |
|
1231 (a[i-6] == 'a') && |
|
1232 (a[i-5] == 'n') && |
|
1233 (a[i-4] == 't') && |
|
1234 (a[i-3] == 'i') && |
|
1235 (a[i-2] == 'a') && |
|
1236 (a[i-1] == 't') && |
|
1237 (a[i] == 'e')) { |
|
1238 matchlen = 11; |
|
1239 mask |= Instantiate; |
|
1240 } else if (i >= 10 && /* queryMBeans */ |
|
1241 (a[i-10] == 'q') && |
|
1242 (a[i-9] == 'u') && |
|
1243 (a[i-8] == 'e') && |
|
1244 (a[i-7] == 'r') && |
|
1245 (a[i-6] == 'y') && |
|
1246 (a[i-5] == 'M') && |
|
1247 (a[i-4] == 'B') && |
|
1248 (a[i-3] == 'e') && |
|
1249 (a[i-2] == 'a') && |
|
1250 (a[i-1] == 'n') && |
|
1251 (a[i] == 's')) { |
|
1252 matchlen = 11; |
|
1253 mask |= QueryMBeans; |
|
1254 } else if (i >= 9 && /* queryNames */ |
|
1255 (a[i-9] == 'q') && |
|
1256 (a[i-8] == 'u') && |
|
1257 (a[i-7] == 'e') && |
|
1258 (a[i-6] == 'r') && |
|
1259 (a[i-5] == 'y') && |
|
1260 (a[i-4] == 'N') && |
|
1261 (a[i-3] == 'a') && |
|
1262 (a[i-2] == 'm') && |
|
1263 (a[i-1] == 'e') && |
|
1264 (a[i] == 's')) { |
|
1265 matchlen = 10; |
|
1266 mask |= QueryNames; |
|
1267 } else if (i >= 5 && /* invoke */ |
|
1268 (a[i-5] == 'i') && |
|
1269 (a[i-4] == 'n') && |
|
1270 (a[i-3] == 'v') && |
|
1271 (a[i-2] == 'o') && |
|
1272 (a[i-1] == 'k') && |
|
1273 (a[i] == 'e')) { |
|
1274 matchlen = 6; |
|
1275 mask |= Invoke; |
|
1276 } else { |
|
1277 // parse error |
|
1278 throw new IllegalArgumentException("Invalid permission: " + |
|
1279 action); |
|
1280 } |
|
1281 |
|
1282 // make sure we didn't just match the tail of a word |
|
1283 // like "ackbarfaccept". Also, skip to the comma. |
|
1284 boolean seencomma = false; |
|
1285 while (i >= matchlen && !seencomma) { |
|
1286 switch(a[i-matchlen]) { |
|
1287 case ',': |
|
1288 seencomma = true; |
|
1289 break; |
|
1290 case ' ': case '\r': case '\n': |
|
1291 case '\f': case '\t': |
|
1292 break; |
|
1293 default: |
|
1294 throw new IllegalArgumentException("Invalid permission: " + |
|
1295 action); |
|
1296 } |
|
1297 i--; |
|
1298 } |
|
1299 |
|
1300 // point i at the location of the comma minus one (or -1). |
|
1301 i -= matchlen; |
|
1302 } |
|
1303 |
|
1304 return mask; |
|
1305 } |
|
1306 |
|
1307 /** |
|
1308 * <p>Checks if this JMXNamespacePermission object "implies" the |
|
1309 * specified permission.</p> |
|
1310 * |
|
1311 * <p>More specifically, this method returns true if:</p> |
|
1312 * |
|
1313 * <ul> |
|
1314 * |
|
1315 * <li> <i>p</i> is an instance of JMXNamespacePermission; and</li> |
|
1316 * |
|
1317 * <li> <i>p</i> has a null mbeanServerName or <i>p</i>'s mbeanServerName |
|
1318 * matches this object's mbeanServerName; and</li> |
|
1319 * |
|
1320 * <li> <i>p</i> has a null member or <i>p</i>'s member matches this |
|
1321 * object's member; and</li> |
|
1322 * |
|
1323 * <li> <i>p</i> has a null object name or <i>p</i>'s |
|
1324 * object name matches this object's object name; and</li> |
|
1325 * |
|
1326 * <li> <i>p</i>'s actions are a subset of this object's actions</li> |
|
1327 * |
|
1328 * </ul> |
|
1329 * |
|
1330 * <p>If this object's mbeanServerName is a pattern, then <i>p</i>'s |
|
1331 * mbeanServerName is matched against that pattern. An empty |
|
1332 * mbeanServerName is equivalent to "{@code *}". A null |
|
1333 * mbeanServerName is equivalent to "{@code -}".</p> |
|
1334 * <p>If this object's mbeanServerName is "<code>*</code>" or is |
|
1335 * empty, <i>p</i>'s mbeanServerName always matches it.</p> |
|
1336 * |
|
1337 * <p>If this object's member is "<code>*</code>", <i>p</i>'s |
|
1338 * member always matches it.</p> |
|
1339 * |
|
1340 * <p>If this object's objectName <i>n1</i> is an object name pattern, |
|
1341 * <i>p</i>'s objectName <i>n2</i> matches it if |
|
1342 * {@link ObjectName#equals <i>n1</i>.equals(<i>n2</i>)} or if |
|
1343 * {@link ObjectName#apply <i>n1</i>.apply(<i>n2</i>)}.</p> |
|
1344 * |
|
1345 * <p>A permission that includes the <code>queryMBeans</code> action |
|
1346 * is considered to include <code>queryNames</code> as well.</p> |
|
1347 * |
|
1348 * @param p the permission to check against. |
|
1349 * @return true if the specified permission is implied by this object, |
|
1350 * false if not. |
|
1351 */ |
|
1352 public boolean implies(Permission p) { |
|
1353 if (!(p instanceof JMXNamespacePermission)) |
|
1354 return false; |
|
1355 |
|
1356 JMXNamespacePermission that = (JMXNamespacePermission) p; |
|
1357 |
|
1358 // Actions |
|
1359 // |
|
1360 // The actions in 'this' permission must be a |
|
1361 // superset of the actions in 'that' permission |
|
1362 // |
|
1363 |
|
1364 /* "queryMBeans" implies "queryNames" */ |
|
1365 if ((this.mask & QueryMBeans) == QueryMBeans) { |
|
1366 if (((this.mask | QueryNames) & that.mask) != that.mask) { |
|
1367 //System.out.println("action [with QueryNames] does not imply"); |
|
1368 return false; |
|
1369 } |
|
1370 } else { |
|
1371 if ((this.mask & that.mask) != that.mask) { |
|
1372 //System.out.println("action does not imply"); |
|
1373 return false; |
|
1374 } |
|
1375 } |
|
1376 |
|
1377 // Target name |
|
1378 // |
|
1379 // The 'mbeanServerName' check is true iff: |
|
1380 // 1) the mbeanServerName in 'this' permission is omitted or "*", or |
|
1381 // 2) the mbeanServerName in 'that' permission is omitted or "*", or |
|
1382 // 3) the mbeanServerName in 'this' permission does pattern |
|
1383 // matching with the mbeanServerName in 'that' permission. |
|
1384 // |
|
1385 // The 'member' check is true iff: |
|
1386 // 1) the member in 'this' member is omitted or "*", or |
|
1387 // 2) the member in 'that' member is omitted or "*", or |
|
1388 // 3) the member in 'this' permission equals the member in |
|
1389 // 'that' permission. |
|
1390 // |
|
1391 // The 'object name' check is true iff: |
|
1392 // 1) the object name in 'this' permission is omitted, or |
|
1393 // 2) the object name in 'that' permission is omitted, or |
|
1394 // 3) the object name in 'this' permission does pattern |
|
1395 // matching with the object name in 'that' permission. |
|
1396 // |
|
1397 |
|
1398 if (that.mbeanServerName == null) { |
|
1399 // bottom is implied |
|
1400 } else if (this.mbeanServerName == null) { |
|
1401 // bottom implies nothing but itself |
|
1402 return false; |
|
1403 } else if (that.mbeanServerName.equals(this.mbeanServerName)) { |
|
1404 // exact match |
|
1405 } else if (!Util.wildmatch(that.mbeanServerName,this.mbeanServerName)) { |
|
1406 return false; // no match |
|
1407 } |
|
1408 |
|
1409 /* Check if this.member implies that.member */ |
|
1410 |
|
1411 if (that.member == null) { |
|
1412 // bottom is implied |
|
1413 } else if (this.member == null) { |
|
1414 // bottom implies nothing but itself |
|
1415 return false; |
|
1416 } else if (this.member.equals("*")) { |
|
1417 // wildcard implies everything (including itself) |
|
1418 } else if (this.member.equals(that.member)) { |
|
1419 // exact match |
|
1420 } else if (!Util.wildmatch(that.member,this.member)) { |
|
1421 return false; // no match |
|
1422 } |
|
1423 |
|
1424 /* Check if this.objectName implies that.objectName */ |
|
1425 |
|
1426 if (that.objectName == null) { |
|
1427 // bottom is implied |
|
1428 } else if (this.objectName == null) { |
|
1429 // bottom implies nothing but itself |
|
1430 if (allnames == false) return false; |
|
1431 } else if (!this.objectName.apply(that.objectName)) { |
|
1432 /* ObjectName.apply returns false if that.objectName is a |
|
1433 wildcard so we also allow equals for that case. This |
|
1434 never happens during real permission checks, but means |
|
1435 the implies relation is reflexive. */ |
|
1436 if (!this.objectName.equals(that.objectName)) |
|
1437 return false; |
|
1438 } |
|
1439 |
|
1440 return true; |
|
1441 } |
|
1442 |
|
1443 /** |
|
1444 * Checks two JMXNamespacePermission objects for equality. Checks |
|
1445 * that <i>obj</i> is an JMXNamespacePermission, and has the same |
|
1446 * name and actions as this object. |
|
1447 * <P> |
|
1448 * @param obj the object we are testing for equality with this object. |
|
1449 * @return true if obj is an JMXNamespacePermission, and has the |
|
1450 * same name and actions as this JMXNamespacePermission object. |
|
1451 */ |
|
1452 public boolean equals(Object obj) { |
|
1453 if (obj == this) |
|
1454 return true; |
|
1455 |
|
1456 if (! (obj instanceof JMXNamespacePermission)) |
|
1457 return false; |
|
1458 |
|
1459 JMXNamespacePermission that = (JMXNamespacePermission) obj; |
|
1460 |
|
1461 return (this.mask == that.mask) && |
|
1462 (this.getName().equals(that.getName())); |
|
1463 } |
|
1464 |
|
1465 /** |
|
1466 * Deserialize this object based on its name and actions. |
|
1467 */ |
|
1468 private void readObject(ObjectInputStream in) |
|
1469 throws IOException, ClassNotFoundException { |
|
1470 in.defaultReadObject(); |
|
1471 parseName(); |
|
1472 parseActions(); |
|
1473 } |
|
1474 } |