1. /*
  2. * @(#)Permissions.java 1.40 01/11/29
  3. *
  4. * Copyright 2002 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. package java.security;
  8. import java.util.Enumeration;
  9. import java.util.Hashtable;
  10. import java.util.NoSuchElementException;
  11. import java.io.Serializable;
  12. import java.util.ArrayList;
  13. /**
  14. * This class represents a heterogeneous collection of Permissions. That is,
  15. * it contains different types of Permission objects, organized into
  16. * PermissionCollections. For example, if any <code>java.io.FilePermission</code>
  17. * objects are added to an instance of this class, they are all stored in a single
  18. * PermissionCollection. It is the PermissionCollection returned by a call to
  19. * the <code>newPermissionCollection</code> method in the FilePermission class.
  20. * Similarly, any <code>java.lang.RuntimePermission</code> objects are stored in
  21. * the PermissionCollection returned by a call to the
  22. * <code>newPermissionCollection</code> method in the
  23. * RuntimePermission class. Thus, this class represents a collection of
  24. * PermissionCollections.
  25. *
  26. * <p>When the <code>add</code> method is called to add a Permission, the
  27. * Permission is stored in the appropriate PermissionCollection. If no such
  28. * collection exists yet, the Permission object's class is determined and the
  29. * <code>newPermissionCollection</code> method is called on that class to create
  30. * the PermissionCollection and add it to the Permissions object. If
  31. * <code>newPermissionCollection</code> returns null, then a default
  32. * PermissionCollection that uses a hashtable will be created and used. Each
  33. * hashtable entry stores a Permission object as both the key and the value.
  34. *
  35. * @see Permission
  36. * @see PermissionCollection
  37. * @see AllPermission
  38. *
  39. * @version 1.40, 01/11/29
  40. *
  41. * @author Marianne Mueller
  42. * @author Roland Schemers
  43. */
  44. public final class Permissions extends PermissionCollection
  45. implements Serializable
  46. {
  47. private Hashtable perms;
  48. // optimization. keep track of the AllPermission collection
  49. private PermissionCollection allPermission;
  50. /**
  51. * Creates a new Permissions object containing no PermissionCollections.
  52. */
  53. public Permissions() {
  54. perms = new Hashtable(11);
  55. allPermission = null;
  56. }
  57. /**
  58. * Adds a permission object to the PermissionCollection for the class the
  59. * permission belongs to. For example, if <i>permission</i> is a FilePermission,
  60. * it is added to the FilePermissionCollection stored in this
  61. * Permissions object.
  62. *
  63. * This method creates
  64. * a new PermissionCollection object (and adds the permission to it)
  65. * if an appropriate collection does not yet exist. <p>
  66. *
  67. * @param permission the Permission object to add.
  68. *
  69. * @exception SecurityException if this Permissions object is
  70. * marked as readonly.
  71. *
  72. * @see isReadOnly
  73. */
  74. public void add(Permission permission) {
  75. if (isReadOnly())
  76. throw new SecurityException(
  77. "attempt to add a Permission to a readonly Permissions object");
  78. PermissionCollection pc = getPermissionCollection(permission);
  79. pc.add(permission);
  80. if (permission instanceof AllPermission) {
  81. allPermission = pc;
  82. }
  83. }
  84. /**
  85. * Checks to see if this object's PermissionCollection for permissions of the
  86. * specified permission's type implies the permissions
  87. * expressed in the <i>permission</i> object. Returns true if the combination
  88. * of permissions in the appropriate PermissionCollection (e.g., a
  89. * FilePermissionCollection for a FilePermission) together imply the
  90. * specified permission.
  91. *
  92. * <p>For example, suppose there is a FilePermissionCollection in this Permissions
  93. * object, and it contains one FilePermission that specifies "read" access for
  94. * all files in all subdirectories of the "/tmp" directory, and another
  95. * FilePermission that specifies "write" access for all files in the
  96. * "/tmp/scratch/foo" directory. Then if the <code>implies</code> method
  97. * is called with a permission specifying both "read" and "write" access
  98. * to files in the "/tmp/scratch/foo" directory, <code>true</code> is returned.
  99. * <p>Additionally, if this PermissionCollection contains the
  100. * AllPermission, this method will always return true.
  101. * <p>
  102. * @param permission the Permission object to check.
  103. *
  104. * @return true if "permission" is implied by the permissions in the
  105. * PermissionCollection it
  106. * belongs to, false if not.
  107. */
  108. public boolean implies(Permission permission) {
  109. PermissionCollection pc = getPermissionCollection(permission);
  110. if (allPermission != null && allPermission.implies(permission))
  111. return true;
  112. else
  113. return pc.implies(permission);
  114. }
  115. /**
  116. * Returns an enumeration of all the Permission objects in all the
  117. * PermissionCollections in this Permissions object.
  118. *
  119. * @return an enumeration of all the Permissions.
  120. */
  121. public Enumeration elements() {
  122. // go through each Permissions in the hash table
  123. // and call their elements() function.
  124. return new PermissionsEnumerator(perms.elements());
  125. }
  126. /**
  127. * Returns an enumeration of all the Permission objects with the same
  128. * type as <i>p</i>.
  129. *
  130. * @param p the prototype Permission object.
  131. *
  132. * @return an enumeration of all the Permissions with the same type as <i>p</i>.
  133. */
  134. // XXX this could be public. Question is, do we want to make it public?
  135. // it is currently trivial to implement, but that might change...
  136. private Enumeration elements(Permission p) {
  137. PermissionCollection pc = getPermissionCollection(p);
  138. return pc.elements();
  139. }
  140. /**
  141. * Gets the PermissionCollection in this Permissions object for
  142. * permissions whose type is the same as that of <i>p</i>.
  143. * For example, if <i>p</i> is a FilePermission, the FilePermissionCollection
  144. * stored in this Permissions object will be returned.
  145. *
  146. * This method creates a new PermissionCollection object for the specified
  147. * type of permission objects if one does not yet exist.
  148. * To do so, it first calls the <code>newPermissionCollection</code> method
  149. * on <i>p</i>. Subclasses of class Permission
  150. * override that method if they need to store their permissions in a particular
  151. * PermissionCollection object in order to provide the correct semantics
  152. * when the <code>PermissionCollection.implies</code> method is called.
  153. * If the call returns a PermissionCollection, that collection is stored
  154. * in this Permissions object. If the call returns null, then
  155. * this method instantiates and stores a default PermissionCollection
  156. * that uses a hashtable to store its permission objects.
  157. */
  158. private PermissionCollection getPermissionCollection(Permission p) {
  159. Class c = p.getClass();
  160. PermissionCollection pc = (PermissionCollection) perms.get(c);
  161. if (pc == null) {
  162. synchronized (perms) {
  163. // check again, in case someone else created one
  164. // between the time we checked and the time we
  165. // got the lock. We do this here to avoid
  166. // making this whole method synchronized, because
  167. // it is called by every public method.
  168. pc = (PermissionCollection) perms.get(c);
  169. //check for unresolved permissions
  170. if (pc == null) {
  171. pc = getUnresolvedPermissions(p);
  172. // if still null, create a new collection
  173. if (pc == null) {
  174. pc = p.newPermissionCollection();
  175. // still no PermissionCollection?
  176. // We'll give them a PermissionsHash.
  177. if (pc == null)
  178. pc = new PermissionsHash();
  179. }
  180. }
  181. perms.put(c, pc);
  182. }
  183. }
  184. return pc;
  185. }
  186. /**
  187. * Resolves any unresolved permissions of type p.
  188. *
  189. * @param p the type of unresolved permission to resolve
  190. *
  191. * @return PermissionCollection containing the unresolved permissions,
  192. * or null if there were no unresolved permissions of type p.
  193. *
  194. */
  195. private PermissionCollection getUnresolvedPermissions(Permission p)
  196. {
  197. UnresolvedPermissionCollection uc =
  198. (UnresolvedPermissionCollection) perms.get(UnresolvedPermission.class);
  199. // we have no unresolved permissions if uc is null
  200. if (uc == null)
  201. return null;
  202. java.util.Vector v = uc.getUnresolvedPermissions(p);
  203. // we have no unresolved permissions of this type if v is null
  204. if (v == null)
  205. return null;
  206. java.security.cert.Certificate certs[] = null;
  207. Object signers[] = p.getClass().getSigners();
  208. int n = 0;
  209. if (signers != null) {
  210. for (int j=0; j < signers.length; j++) {
  211. if (signers[j] instanceof java.security.cert.Certificate) {
  212. n++;
  213. }
  214. }
  215. certs = new java.security.cert.Certificate[n];
  216. n = 0;
  217. for (int j=0; j < signers.length; j++) {
  218. if (signers[j] instanceof java.security.cert.Certificate) {
  219. certs[n++] = (java.security.cert.Certificate)signers[j];
  220. }
  221. }
  222. }
  223. PermissionCollection pc = null;
  224. Enumeration e = v.elements();
  225. while(e.hasMoreElements()) {
  226. UnresolvedPermission up = (UnresolvedPermission) e.nextElement();
  227. Permission perm = up.resolve(p, certs);
  228. if (perm != null) {
  229. if (pc == null) {
  230. pc = p.newPermissionCollection();
  231. if (pc == null)
  232. pc = new PermissionsHash();
  233. }
  234. pc.add(perm);
  235. }
  236. }
  237. return pc;
  238. }
  239. }
  240. final class PermissionsEnumerator implements Enumeration {
  241. // all the perms
  242. private Enumeration perms;
  243. // the current set
  244. private Enumeration permset;
  245. PermissionsEnumerator(Enumeration e) {
  246. perms = e;
  247. permset = getNextEnumWithMore();
  248. }
  249. public synchronized boolean hasMoreElements() {
  250. // if we enter with permissionimpl null, we know
  251. // there are no more left.
  252. if (permset == null)
  253. return false;
  254. // try to see if there are any left in the current one
  255. if (permset.hasMoreElements())
  256. return true;
  257. // get the next one that has something in it...
  258. permset = getNextEnumWithMore();
  259. // if it is null, we are done!
  260. return (permset != null);
  261. }
  262. public synchronized Object nextElement() {
  263. // hasMoreElements will update permset to the next permset
  264. // with something in it...
  265. if (hasMoreElements()) {
  266. return permset.nextElement();
  267. } else {
  268. throw new NoSuchElementException("PermissionsEnumerator");
  269. }
  270. }
  271. private Enumeration getNextEnumWithMore() {
  272. while (perms.hasMoreElements()) {
  273. PermissionCollection pc = (PermissionCollection) perms.nextElement();
  274. Enumeration next = (Enumeration) pc.elements();
  275. if (next.hasMoreElements())
  276. return next;
  277. }
  278. return null;
  279. }
  280. }
  281. /**
  282. * A PermissionsHash stores a homogeneous set of permissions in a hashtable.
  283. *
  284. * @see Permission
  285. * @see Permissions
  286. *
  287. * @version 1.40, 02/10/07
  288. *
  289. * @author Roland Schemers
  290. */
  291. final class PermissionsHash extends PermissionCollection
  292. implements Serializable
  293. {
  294. private Hashtable perms;
  295. /**
  296. * Create an empty PermissionsHash object.
  297. */
  298. PermissionsHash() {
  299. perms = new Hashtable(11);
  300. }
  301. /**
  302. * Adds a permission to the PermissionsHash.
  303. *
  304. * @param permission the Permission object to add.
  305. */
  306. public void add(Permission permission)
  307. {
  308. perms.put(permission, permission);
  309. }
  310. /**
  311. * Check and see if this set of permissions implies the permissions
  312. * expressed in "permission".
  313. *
  314. * @param permission the Permission object to compare
  315. *
  316. * @return true if "permission" is a proper subset of a permission in
  317. * the set, false if not.
  318. */
  319. public boolean implies(Permission permission)
  320. {
  321. // attempt a fast lookup and implies. If that fails
  322. // then enumerate through all the permissions.
  323. Permission p = (Permission) perms.get(permission);
  324. if ((p == null) || (!p.implies(permission))) {
  325. Enumeration enum = elements();
  326. try {
  327. while (enum.hasMoreElements()) {
  328. p = (Permission) enum.nextElement();
  329. if (p.implies(permission))
  330. return true;
  331. }
  332. } catch (NoSuchElementException e){
  333. // ignore
  334. }
  335. return false;
  336. } else {
  337. return true;
  338. }
  339. }
  340. /**
  341. * Returns an enumeration of all the Permission objects in the container.
  342. *
  343. * @return an enumeration of all the Permissions.
  344. */
  345. public Enumeration elements()
  346. {
  347. return perms.elements();
  348. }
  349. }