1. /*
  2. * @(#)BasicPermission.java 1.37 03/01/23
  3. *
  4. * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. package java.security;
  8. import java.security.*;
  9. import java.util.Enumeration;
  10. import java.util.Iterator;
  11. import java.util.Map;
  12. import java.util.HashMap;
  13. import java.util.Hashtable;
  14. import java.util.Collections;
  15. import java.util.StringTokenizer;
  16. import java.io.ObjectStreamField;
  17. import java.io.ObjectOutputStream;
  18. import java.io.ObjectInputStream;
  19. import java.io.IOException;
  20. /**
  21. * The BasicPermission class extends the Permission class, and
  22. * can be used as the base class for permissions that want to
  23. * follow the same naming convention as BasicPermission.
  24. * <P>
  25. * The name for a BasicPermission is the name of the given permission
  26. * (for example, "exit",
  27. * "setFactory", "print.queueJob", etc). The naming
  28. * convention follows the hierarchical property naming convention.
  29. * An asterisk may appear by itself, or if immediately preceded by a "."
  30. * may appear at the end of the name, to signify a wildcard match.
  31. * For example, "*" and "java.*" are valid, while "*java", "a*b",
  32. * and "java*" are not valid.
  33. * <P>
  34. * The action string (inherited from Permission) is unused.
  35. * Thus, BasicPermission is commonly used as the base class for
  36. * "named" permissions
  37. * (ones that contain a name but no actions list; you either have the
  38. * named permission or you don't.)
  39. * Subclasses may implement actions on top of BasicPermission,
  40. * if desired.
  41. * <p>
  42. * <P>
  43. * @see java.security.Permission
  44. * @see java.security.Permissions
  45. * @see java.security.PermissionCollection
  46. * @see java.lang.RuntimePermission
  47. * @see java.security.SecurityPermission
  48. * @see java.util.PropertyPermission
  49. * @see java.awt.AWTPermission
  50. * @see java.net.NetPermission
  51. * @see java.lang.SecurityManager
  52. *
  53. * @version 1.37 03/01/23
  54. *
  55. * @author Marianne Mueller
  56. * @author Roland Schemers
  57. */
  58. public abstract class BasicPermission extends Permission
  59. implements java.io.Serializable
  60. {
  61. // does this permission have a wildcard at the end?
  62. private transient boolean wildcard;
  63. // the name without the wildcard on the end
  64. private transient String path;
  65. /**
  66. * initialize a BasicPermission object. Common to all constructors.
  67. *
  68. */
  69. private void init(String name)
  70. {
  71. if (name == null)
  72. throw new NullPointerException("name can't be null");
  73. int len = name.length();
  74. if (len == 0) {
  75. throw new IllegalArgumentException("name can't be empty");
  76. }
  77. char last = name.charAt(len - 1);
  78. // Is wildcard or ends with ".*"?
  79. if (last == '*' && (len == 1 || name.charAt(len - 2) == '.')) {
  80. wildcard = true;
  81. if (len == 1) {
  82. path = "";
  83. } else {
  84. path = name.substring(0, len - 1);
  85. }
  86. } else {
  87. path = name;
  88. }
  89. }
  90. /**
  91. * Creates a new BasicPermission with the specified name.
  92. * Name is the symbolic name of the permission, such as
  93. * "setFactory",
  94. * "print.queueJob", or "topLevelWindow", etc.
  95. *
  96. * @param name the name of the BasicPermission.
  97. *
  98. * @throws NullPointerException if <code>name</code> is <code>null</code>.
  99. * @throws IllegalArgumentException if <code>name</code> is empty.
  100. */
  101. public BasicPermission(String name)
  102. {
  103. super(name);
  104. init(name);
  105. }
  106. /**
  107. * Creates a new BasicPermission object with the specified name.
  108. * The name is the symbolic name of the BasicPermission, and the
  109. * actions String is currently unused.
  110. *
  111. * @param name the name of the BasicPermission.
  112. * @param actions ignored.
  113. *
  114. * @throws NullPointerException if <code>name</code> is <code>null</code>.
  115. * @throws IllegalArgumentException if <code>name</code> is empty.
  116. */
  117. public BasicPermission(String name, String actions)
  118. {
  119. super(name);
  120. init(name);
  121. }
  122. /**
  123. * Checks if the specified permission is "implied" by
  124. * this object.
  125. * <P>
  126. * More specifically, this method returns true if:<p>
  127. * <ul>
  128. * <li> <i>p</i>'s class is the same as this object's class, and<p>
  129. * <li> <i>p</i>'s name equals or (in the case of wildcards)
  130. * is implied by this object's
  131. * name. For example, "a.b.*" implies "a.b.c".
  132. * </ul>
  133. *
  134. * @param p the permission to check against.
  135. *
  136. * @return true if the passed permission is equal to or
  137. * implied by this permission, false otherwise.
  138. */
  139. public boolean implies(Permission p) {
  140. if ((p == null) || (p.getClass() != getClass()))
  141. return false;
  142. BasicPermission that = (BasicPermission) p;
  143. if (this.wildcard) {
  144. if (that.wildcard)
  145. // one wildcard can imply another
  146. return that.path.startsWith(path);
  147. else
  148. // make sure ap.path is longer so a.b.* doesn't imply a.b
  149. return (that.path.length() > this.path.length()) &&
  150. that.path.startsWith(this.path);
  151. } else {
  152. if (that.wildcard) {
  153. // a non-wildcard can't imply a wildcard
  154. return false;
  155. }
  156. else {
  157. return this.path.equals(that.path);
  158. }
  159. }
  160. }
  161. /**
  162. * Checks two BasicPermission objects for equality.
  163. * Checks that <i>obj</i>'s class is the same as this object's class
  164. * and has the same name as this object.
  165. * <P>
  166. * @param obj the object we are testing for equality with this object.
  167. * @return true if <i>obj</i> is a BasicPermission, and has the same name
  168. * as this BasicPermission object, false otherwise.
  169. */
  170. public boolean equals(Object obj) {
  171. if (obj == this)
  172. return true;
  173. if ((obj == null) || (obj.getClass() != getClass()))
  174. return false;
  175. BasicPermission bp = (BasicPermission) obj;
  176. return getName().equals(bp.getName());
  177. }
  178. /**
  179. * Returns the hash code value for this object.
  180. * The hash code used is the hash code of the name, that is,
  181. * <code>getName().hashCode()</code>, where <code>getName</code> is
  182. * from the Permission superclass.
  183. *
  184. * @return a hash code value for this object.
  185. */
  186. public int hashCode() {
  187. return this.getName().hashCode();
  188. }
  189. /**
  190. * Returns the canonical string representation of the actions,
  191. * which currently is the empty string "", since there are no actions for
  192. * a BasicPermission.
  193. *
  194. * @return the empty string "".
  195. */
  196. public String getActions()
  197. {
  198. return "";
  199. }
  200. /**
  201. * Returns a new PermissionCollection object for storing BasicPermission
  202. * objects.
  203. * <p>
  204. * A BasicPermissionCollection stores a collection of
  205. * BasicPermission permissions.
  206. *
  207. * <p>BasicPermission objects must be stored in a manner that allows them
  208. * to be inserted in any order, but that also enables the
  209. * PermissionCollection <code>implies</code> method
  210. * to be implemented in an efficient (and consistent) manner.
  211. *
  212. * @return a new PermissionCollection object suitable for
  213. * storing BasicPermissions.
  214. */
  215. public PermissionCollection newPermissionCollection() {
  216. return new BasicPermissionCollection();
  217. }
  218. /**
  219. * readObject is called to restore the state of the BasicPermission from
  220. * a stream.
  221. */
  222. private void readObject(ObjectInputStream s)
  223. throws IOException, ClassNotFoundException
  224. {
  225. s.defaultReadObject();
  226. // init is called to initialize the rest of the values.
  227. init(getName());
  228. }
  229. }
  230. /**
  231. * A BasicPermissionCollection stores a collection
  232. * of BasicPermission permissions. BasicPermission objects
  233. * must be stored in a manner that allows them to be inserted in any
  234. * order, but enable the implies function to evaluate the implies
  235. * method in an efficient (and consistent) manner.
  236. *
  237. * A BasicPermissionCollection handles comparing a permission like "a.b.c.d.e"
  238. * with a Permission such as "a.b.*", or "*".
  239. *
  240. * @see java.security.Permission
  241. * @see java.security.Permissions
  242. * @see java.security.PermissionsImpl
  243. *
  244. * @version 1.37 01/23/03
  245. *
  246. * @author Roland Schemers
  247. *
  248. * @serial include
  249. */
  250. final class BasicPermissionCollection
  251. extends PermissionCollection
  252. implements java.io.Serializable
  253. {
  254. private static final long serialVersionUID = 739301742472979399L;
  255. /**
  256. * Key is name, value is permission. All permission objects in
  257. * collection must be of the same type.
  258. * Not serialized; see serialization section at end of class.
  259. */
  260. private transient Map perms;
  261. /**
  262. * This is set to <code>true</code> if this BasicPermissionCollection
  263. * contains a BasicPermission with '*' as its permission name.
  264. *
  265. * @see #serialPersistentFields
  266. */
  267. private boolean all_allowed;
  268. /**
  269. * The class to which all BasicPermissions in this
  270. * BasicPermissionCollection belongs.
  271. *
  272. * @see #serialPersistentFields
  273. */
  274. private Class permClass;
  275. /**
  276. * Create an empty BasicPermissionCollection object.
  277. *
  278. */
  279. public BasicPermissionCollection() {
  280. perms = new HashMap(11);
  281. all_allowed = false;
  282. }
  283. /**
  284. * Adds a permission to the BasicPermissions. The key for the hash is
  285. * permission.path.
  286. *
  287. * @param permission the Permission object to add.
  288. *
  289. * @exception IllegalArgumentException - if the permission is not a
  290. * BasicPermission, or if
  291. * the permission is not of the
  292. * same Class as the other
  293. * permissions in this collection.
  294. *
  295. * @exception SecurityException - if this BasicPermissionCollection object
  296. * has been marked readonly
  297. */
  298. public void add(Permission permission)
  299. {
  300. if (! (permission instanceof BasicPermission))
  301. throw new IllegalArgumentException("invalid permission: "+
  302. permission);
  303. if (isReadOnly())
  304. throw new SecurityException("attempt to add a Permission to a readonly PermissionCollection");
  305. BasicPermission bp = (BasicPermission) permission;
  306. if (perms.size() == 0) {
  307. // adding first permission
  308. permClass = bp.getClass();
  309. } else {
  310. // make sure we only add new BasicPermissions of the same class
  311. if (bp.getClass() != permClass)
  312. throw new IllegalArgumentException("invalid permission: " +
  313. permission);
  314. }
  315. // No need to synchronize because all adds are done sequentially
  316. // before any implies() calls
  317. perms.put(bp.getName(), permission);
  318. if (!all_allowed) {
  319. if (bp.getName().equals("*"))
  320. all_allowed = true;
  321. }
  322. }
  323. /**
  324. * Check and see if this set of permissions implies the permissions
  325. * expressed in "permission".
  326. *
  327. * @param p the Permission object to compare
  328. *
  329. * @return true if "permission" is a proper subset of a permission in
  330. * the set, false if not.
  331. */
  332. public boolean implies(Permission permission)
  333. {
  334. if (! (permission instanceof BasicPermission))
  335. return false;
  336. BasicPermission bp = (BasicPermission) permission;
  337. // random subclasses of BasicPermission do not imply each other
  338. if (bp.getClass() != permClass)
  339. return false;
  340. // short circuit if the "*" Permission was added
  341. if (all_allowed)
  342. return true;
  343. // strategy:
  344. // Check for full match first. Then work our way up the
  345. // path looking for matches on a.b..*
  346. String path = bp.getName();
  347. //System.out.println("check "+path);
  348. Permission x = (Permission) perms.get(path);
  349. if (x != null) {
  350. // we have a direct hit!
  351. return x.implies(permission);
  352. }
  353. // work our way up the tree...
  354. int last, offset;
  355. offset = path.length()-1;
  356. while ((last = path.lastIndexOf(".", offset)) != -1) {
  357. path = path.substring(0, last+1) + "*";
  358. //System.out.println("check "+path);
  359. x = (Permission) perms.get(path);
  360. if (x != null) {
  361. return x.implies(permission);
  362. }
  363. offset = last -1;
  364. }
  365. // we don't have to check for "*" as it was already checked
  366. // at the top (all_allowed), so we just return false
  367. return false;
  368. }
  369. /**
  370. * Returns an enumeration of all the BasicPermission objects in the
  371. * container.
  372. *
  373. * @return an enumeration of all the BasicPermission objects.
  374. */
  375. public Enumeration elements() {
  376. // Convert Iterator of Map values into an Enumeration
  377. return Collections.enumeration(perms.values());
  378. }
  379. // Need to maintain serialization interoperability with earlier releases,
  380. // which had the serializable field:
  381. //
  382. // @serial the Hashtable is indexed by the BasicPermission name
  383. //
  384. // private Hashtable permissions;
  385. /**
  386. * @serialField permissions java.util.Hashtable
  387. * The BasicPermissions in this BasicPermissionCollection.
  388. * All BasicPermissions in the collection must belong to the same class.
  389. * The Hashtable is indexed by the BasicPermission name; the value
  390. * of the Hashtable entry is the permission.
  391. * @serialField all_allowed boolean
  392. * This is set to <code>true</code> if this BasicPermissionCollection
  393. * contains a BasicPermission with '*' as its permission name.
  394. * @serialField permClass java.lang.Class
  395. * The class to which all BasicPermissions in this
  396. * BasicPermissionCollection belongs.
  397. */
  398. private static final ObjectStreamField[] serialPersistentFields = {
  399. new ObjectStreamField("permissions", Hashtable.class),
  400. new ObjectStreamField("all_allowed", Boolean.TYPE),
  401. new ObjectStreamField("permClass", Class.class),
  402. };
  403. /**
  404. * @serialData Default fields.
  405. */
  406. /*
  407. * Writes the contents of the perms field out as a Hashtable for
  408. * serialization compatibility with earlier releases. all_allowed
  409. * and permClass unchanged.
  410. */
  411. private void writeObject(ObjectOutputStream out) throws IOException {
  412. // Don't call out.defaultWriteObject()
  413. // Copy perms into a Hashtable
  414. Hashtable permissions = new Hashtable(perms.size()*2);
  415. permissions.putAll(perms);
  416. // Write out serializable fields
  417. ObjectOutputStream.PutField pfields = out.putFields();
  418. pfields.put("all_allowed", all_allowed);
  419. pfields.put("permissions", permissions);
  420. pfields.put("permClass", permClass);
  421. out.writeFields();
  422. }
  423. /**
  424. * readObject is called to restore the state of the
  425. * BasicPermissionCollection from a stream.
  426. */
  427. private void readObject(java.io.ObjectInputStream in)
  428. throws IOException, ClassNotFoundException
  429. {
  430. // Don't call defaultReadObject()
  431. // Read in serialized fields
  432. ObjectInputStream.GetField gfields = in.readFields();
  433. // Get permissions
  434. Hashtable permissions = (Hashtable)gfields.get("permissions", null);
  435. perms = new HashMap(permissions.size()*2);
  436. perms.putAll(permissions);
  437. // Get all_allowed
  438. all_allowed = gfields.get("all_allowed", false);
  439. // Get permClass
  440. permClass = (Class) gfields.get("permClass", null);
  441. if (permClass == null) {
  442. // set permClass
  443. Enumeration e = permissions.elements();
  444. if (e.hasMoreElements()) {
  445. Permission p = (Permission)e.nextElement();
  446. permClass = p.getClass();
  447. }
  448. }
  449. }
  450. }