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