1 /* MBeanServerPermission.java -- Permissions controlling server creation.
2    Copyright (C) 2006 Free Software Foundation, Inc.
3 
4 This file is part of GNU Classpath.
5 
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
10 
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 General Public License for more details.
15 
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING.  If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 02110-1301 USA.
20 
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library.  Thus, the terms and
23 conditions of the GNU General Public License cover the whole
24 combination.
25 
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module.  An independent module is a module which is not derived from
33 or based on this library.  If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so.  If you do not wish to do so, delete this
36 exception statement from your version. */
37 
38 package javax.management;
39 
40 import java.security.BasicPermission;
41 import java.security.Permission;
42 import java.security.PermissionCollection;
43 
44 import java.util.Enumeration;
45 import java.util.NoSuchElementException;
46 
47 /**
48  * <p>
49  * Represents the permissions required to perform
50  * operations provided by the {@link MBeanServerFactory}.
51  * As with all {@link java.security.Permission} objects, an
52  * instance of this class either represents a permission
53  * already held or one that is required to access a
54  * particular service.  In the case of {@link MBeanServerPermission}s,
55  * implication checks are made using an instance of this class
56  * when a user requests an operation from the factory, and a
57  * {@link SecurityManager} is in place.
58  * </p>
59  * <p>
60  * The permission is defined by its name, which may be
61  * either a <code>'*'</code> (to allow all) or one or
62  * more of the following, separated by a <code>','</code>:
63  * </p>
64  * <ul>
65  * <li><code>createMBeanServer</code> -- allows a registered
66  * instance of a server to be obtained from the factory.</li>
67  * <li><code>findMBeanServer</code> -- allows all or one
68  * particular server instance to be retrieved from the factory.</li>
69  * <li><code>newMBeanServer</code> -- allows an unregistered
70  * instance of a server to be obtained from the factory.</li>
71  * <li><code>releaseMBeanServer</code> -- allows a reference to
72  * a server instance to be removed from the factory.</li>
73  * </ul>
74  * <p>
75  * The names may be surrounded by arbitrary amounts of whitespace.
76  * <code>createMBeanServer</code> implies <code>newMBeanServer</code>.
77  * </p>
78  *
79  * @author Andrew John Hughes (gnu_andrew@member.fsf.org)
80  * @since 1.5
81  */
82 public class MBeanServerPermission
83   extends BasicPermission
84 {
85 
86   /**
87    * Compatible with JDK 1.5
88    */
89   private static final long serialVersionUID = -5661980843569388590L;
90 
91   /**
92    * <p>
93    * Constructs a new {@link MBeanServerPermission} with
94    * the given name.  The name must not be <code>null</code>
95    * and must be equal to either <code>"*"</code> or a
96    * comma-separated list of valid permissions.  The four
97    * valid constraints are:
98    * </p>
99    * <ol>
100    * <li><code>createMBeanServer</code></li>
101    * <li><code>findMBeanServer</code></li>
102    * <li><code>newMBeanServer</code></li>
103    * <li><code>releaseMBeanServer</code></li>
104    * </ol>
105    * <p>
106    * Calling this constructor is equivalent to calling
107    * <code>MBeanPermission(name, null)</code>.
108    * </p>
109    *
110    * @param name the name of this permission.
111    * @throws NullPointerException if <code>name</code>
112    *                              is <code>null</code>.
113    * @throws IllegalArgumentException if <code>name</code>
114    *                                  is not either equal to
115    *                                  <code>"*"</code> or forms
116    *                                  a comma-separated list of
117    *                                  valid constraints.
118    * @see #MBeanServerPermission(String,String)
119    */
MBeanServerPermission(String name)120   public MBeanServerPermission(String name)
121   {
122     this(name, null);
123   }
124 
125   /**
126    * <p>
127    * Constructs a new {@link MBeanServerPermission} with
128    * the given name and actions.  The actions are unused,
129    * and must be either <code>null</code> or the empty
130    * string.  The name must not be <code>null</code>
131    * and must be equal to either <code>"*"</code> or a
132    * comma-separated list of valid permissions.  The four
133    * valid constraints are:
134    * </p>
135    * <ol>
136    * <li><code>createMBeanServer</code></li>
137    * <li><code>findMBeanServer</code></li>
138    * <li><code>newMBeanServer</code></li>
139    * <li><code>releaseMBeanServer</code></li>
140    * </ol>
141    * <p>
142    * Calling this constructor is equivalent to calling
143    * <code>MBeanPermission(name, null)</code>.
144    * </p>
145    *
146    * @param name the name of this permission.
147    * @throws NullPointerException if <code>name</code>
148    *                              is <code>null</code>.
149    * @throws IllegalArgumentException if <code>name</code>
150    *                                  is not either equal to
151    *                                  <code>"*"</code> or forms
152    *                                  a comma-separated list of
153    *                                  valid constraints, or if
154    *                                  <code>actions</code> is not
155    *                                  <code>null</code> or the
156    *                                  empty string.
157    * @see #MBeanServerPermission(String,String)
158    */
MBeanServerPermission(String name, String actions)159   public MBeanServerPermission(String name, String actions)
160   {
161     super(checkName(name), actions);
162     if (actions != null && actions.length() > 0)
163       throw new IllegalArgumentException("The supplied action list " +
164                                          "was not equal to null or the " +
165                                          "empty string.");
166   }
167 
168   /**
169    * Returns true if the given object is also an {@link MBeanServerPermission}
170    * with the same name.
171    *
172    * @param obj the object to compare with this one.
173    * @return true if the object is an {@link MBeanPermission}
174    *         with the same name.
175    */
equals(Object obj)176   public boolean equals(Object obj)
177   {
178     if (obj instanceof MBeanServerPermission)
179       {
180         MBeanServerPermission o = (MBeanServerPermission) obj;
181         return o.getName().equals(getName());
182       }
183     return false;
184   }
185 
186   /**
187    * Returns a unique hash code for this permission.
188    * This is simply the hashcode of {@link BasicPermission#getName()}.
189    *
190    * @return the hashcode of this permission.
191    */
hashCode()192   public int hashCode()
193   {
194     return getName().hashCode();
195   }
196 
197   /**
198    * Returns true if this {@link MBeanServerPermission} implies
199    * the given permission.  This occurs if the given permission
200    * is also an {@link MBeanServerPermission} and its target names
201    * are a subset of the target names of this permission.  Note that
202    * the name <code>createMBeanServer</code> implies
203    * <code>newMBeanServer</code>.
204    *
205    * @param p the permission to check for implication.
206    * @return true if this permission implies <code>p</code>.
207    */
implies(Permission p)208   public boolean implies(Permission p)
209   {
210     if (p instanceof MBeanServerPermission)
211       {
212         if (getName().equals("*"))
213           return true;
214         MBeanServerPermission msp = (MBeanServerPermission) p;
215         String[] thisCaps = getName().split(",");
216         String[] mspCaps = msp.getName().split(",");
217         for (int a = 0; a < mspCaps.length; ++a)
218           {
219             boolean found = false;
220             String mc = mspCaps[a].trim();
221             for (int b = 0; b < thisCaps.length; ++b)
222               {
223                 String tc = thisCaps[b].trim();
224                 if (tc.equals(mc))
225                   found = true;
226                 if (tc.equals("createMBeanServer") &&
227                     mc.equals("newMBeanServer"))
228                   found = true;
229               }
230             if (!found)
231               return false;
232           }
233         return true;
234       }
235     return false;
236   }
237 
238   /**
239    * Returns a {@link PermissionCollection} which stores
240    * a series of {@link MBeanServerPermission}s as the union
241    * of their capabilities.
242    *
243    * @return a collection for {@link MBeanServerPermission}s.
244    */
newPermissionCollection()245   public PermissionCollection newPermissionCollection()
246   {
247     return new MBeanServerPermissionCollection();
248   }
249 
250   /**
251    * A collection of {@link MBeanServerPermission}s, stored
252    * as a single permission with the union of the capabilities
253    * as its capabilities.
254    *
255    * @author Andrew John Hughes (gnu_andrew@member.fsf.org)
256    * @since 1.5
257    */
258   private class MBeanServerPermissionCollection
259     extends PermissionCollection
260   {
261 
262     /**
263      * Compatible with JDK 1.5
264      */
265     private static final long serialVersionUID = -5661980843569388590L;
266 
267     /**
268      * The collected permission.  This is <code>null</code> or
269      * the union of the permissions held by all the collected
270      * permissions.
271      */
272     private MBeanServerPermission collectionPermission;
273 
274     /**
275      * Adds a new permission by unifying it with the existing
276      * collection permission.
277      *
278      * @param p the permission to add.
279      * @throws SecurityException if the collection is read only.
280      * @see #isReadOnly()
281      * @see #setReadOnly(boolean)
282      */
283     @Override
add(Permission p)284     public void add(Permission p)
285     {
286       if (isReadOnly())
287         throw new SecurityException("This collection is read only.");
288       if (p instanceof MBeanServerPermission)
289         {
290           MBeanServerPermission msp = (MBeanServerPermission) p;
291           if (collectionPermission == null)
292             collectionPermission = msp;
293           else
294             {
295               String finalString = collectionPermission.getName();
296               String[] cp = finalString.split(",");
297               String[] np = msp.getName().split(",");
298               int createms = finalString.indexOf("createMBeanServer");
299               int newms = finalString.indexOf("newMBeanServer");
300               for (int a = 0; a < np.length; ++a)
301                 {
302                   boolean found = false;
303                   String nps = np[a].trim();
304                   for (int b = 0; b < cp.length; ++b)
305                     {
306                       String cps = cp[b].trim();
307                       if (cps.equals(nps))
308                         found = true;
309                       if (nps.equals("newMBeanServer")
310                           && createms != -1)
311                         found = true;
312                       if (nps.equals("createMBeanServer")
313                           && newms != -1)
314                         finalString =
315                           finalString.replace("newMBeanServer",
316                                               "createMBeanServer");
317                     }
318                   if (!found)
319                     finalString += "," + nps;
320                 }
321               collectionPermission =
322                 new MBeanServerPermission(finalString);
323             }
324         }
325     }
326 
327     /**
328      * Returns an enumeration over the single permission.
329      *
330      * @return an enumeration over the collection permission.
331      */
332     @Override
elements()333     public Enumeration<Permission> elements()
334     {
335       return new
336         MBeanServerPermissionEnumeration(collectionPermission);
337     }
338 
339     /**
340      * Provides an enumeration over a comma-separated list
341      * of capabilities.
342      *
343      * @author Andrew John Hughes (gnu_andrew@member.fsf.org)
344      * @since 1.5
345      */
346     private class MBeanServerPermissionEnumeration
347       implements Enumeration<Permission>
348     {
349 
350       /**
351        * The collected permission.
352        */
353       private MBeanServerPermission p;
354 
355       /**
356        * True if we have returned the permission.
357        */
358       private boolean done;
359 
360       /**
361        * Constructs a new {@link MBeanServerPermissionEnumeration}
362        * using the given collected permission.
363        *
364        * @param p the collected permission.
365        */
MBeanServerPermissionEnumeration(MBeanServerPermission p)366       public MBeanServerPermissionEnumeration(MBeanServerPermission p)
367       {
368         this.p = p;
369         done = false;
370       }
371 
372       /**
373        * Returns true if there are more capabilities to return.
374        *
375        * @return true if there are more capabilities available.
376        */
hasMoreElements()377       public boolean hasMoreElements()
378       {
379         return !done;
380       }
381 
382       /**
383        * Returns the next capability.
384        *
385        * @return the next capability.
386        */
nextElement()387       public Permission nextElement()
388       {
389         if (hasMoreElements())
390           {
391             done = true;
392             return p;
393           }
394         else
395           throw new NoSuchElementException("No more elements are available.");
396       }
397 
398     }
399 
400     /**
401      * Returns true if the collected {@link MBeanServerPermission}
402      * implies the given permission.  This occurs if the given permission
403      * is also an {@link MBeanServerPermission} and its target names
404      * are a subset of the target names of this permission.  Note that
405      * the name <code>createMBeanServer</code> implies
406      * <code>newMBeanServer</code>.
407      *
408      * @param p the permission to check for implication.
409      * @return true if this permission implies <code>p</code>.
410      */
411     @Override
implies(Permission p)412     public boolean implies(Permission p)
413     {
414       return collectionPermission.implies(p);
415     }
416   }
417 
418   /**
419    * Checks the name is valid, including removing
420    * the <code>newMBeanServer</code> permission when
421    * <code>createMBeanServer</code> is present.
422    *
423    * @param name the name to check.
424    * @throws NullPointerException if <code>name</code>
425    *                              is <code>null</code>.
426    * @throws IllegalArgumentException if <code>name</code>
427    *                                  is not either equal to
428    *                                  <code>"*"</code> or forms
429    *                                  a comma-separated list of
430    *                                  valid constraints.
431    */
checkName(String name)432   private static String checkName(String name)
433   {
434     if (!(name.equals("*")))
435       {
436         String[] constraints = name.split(",");
437         name = "";
438         boolean seenCreate = false;
439         boolean seenNew = false;
440         boolean start = true;
441         for (int a = 0; a < constraints.length; ++a)
442           {
443             String next = constraints[a].trim();
444             if (!(next.equals("createMBeanServer") ||
445                   next.equals("findMBeanServer") ||
446                   next.equals("newMBeanServer") ||
447                   next.equals("releaseMBeanServer")))
448               throw new IllegalArgumentException("An invalid constraint, " +
449                                                  next + ", was specified.");
450             if (next.equals("newMBeanServer"))
451               seenNew = true;
452             else if (next.equals("createMBeanServer"))
453               seenCreate = true;
454             else
455               {
456                 if (!start)
457                   name += ",";
458                 name += next;
459                 start = false;
460               }
461           }
462         if (seenNew && !seenCreate)
463           name += (start ? "" : ",") + "newMBeanServer";
464         else if (seenCreate)
465           name += (start ? "" : ",") + "createMBeanServer";
466       }
467     return name;
468   }
469 
470 }
471