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