1. /*
  2. * @(#)UnresolvedPermission.java 1.16 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.io.IOException;
  9. import java.io.ByteArrayInputStream;
  10. import java.util.ArrayList;
  11. import java.util.Enumeration;
  12. import java.util.Hashtable;
  13. import java.util.Vector;
  14. import java.lang.reflect.*;
  15. import java.security.cert.*;
  16. /**
  17. * The UnresolvedPermission class is used to hold Permissions that
  18. * were "unresolved" when the Policy was initialized.
  19. * An unresolved permission is one whose actual Permission class
  20. * does not yet exist at the time the Policy is initialized (see below).
  21. *
  22. * <p>The policy for a Java runtime (specifying
  23. * which permissions are available for code from various principals)
  24. * is represented by a Policy object.
  25. * Whenever a Policy is initialized or refreshed, Permission objects of
  26. * appropriate classes are created for all permissions
  27. * allowed by the Policy.
  28. *
  29. * <p>Many permission class types
  30. * referenced by the policy configuration are ones that exist
  31. * locally (i.e., ones that can be found on CLASSPATH).
  32. * Objects for such permissions can be instantiated during
  33. * Policy initialization. For example, it is always possible
  34. * to instantiate a java.io.FilePermission, since the
  35. * FilePermission class is found on the CLASSPATH.
  36. *
  37. * <p>Other permission classes may not yet exist during Policy
  38. * initialization. For example, a referenced permission class may
  39. * be in a JAR file that will later be loaded.
  40. * For each such class, an UnresolvedPermission is instantiated.
  41. * Thus, an UnresolvedPermission is essentially a "placeholder"
  42. * containing information about the permission.
  43. *
  44. * <p>Later, when code calls AccessController.checkPermission
  45. * on a permission of a type that was previously unresolved,
  46. * but whose class has since been loaded, previously-unresolved
  47. * permissions of that type are "resolved". That is,
  48. * for each such UnresolvedPermission, a new object of
  49. * the appropriate class type is instantiated, based on the
  50. * information in the UnresolvedPermission. This new object
  51. * replaces the UnresolvedPermission, which is removed.
  52. *
  53. * @see java.security.Permission
  54. * @see java.security.Permissions
  55. * @see java.security.PermissionCollection
  56. * @see java.security.Policy
  57. *
  58. * @version 1.16 01/11/29
  59. *
  60. * @author Roland Schemers
  61. */
  62. public final class UnresolvedPermission extends Permission
  63. implements java.io.Serializable
  64. {
  65. /**
  66. * The class name of the Permission class that will be
  67. * created when this unresolved permission is resolved.
  68. *
  69. * @serial
  70. */
  71. private String type;
  72. /**
  73. * The permission name.
  74. *
  75. * @serial
  76. */
  77. private String name;
  78. /**
  79. * The actions of the permission.
  80. *
  81. * @serial
  82. */
  83. private String actions;
  84. private transient java.security.cert.Certificate certs[];
  85. /**
  86. * Creates a new UnresolvedPermission containing the permission
  87. * information needed later to actually create a Permission of the
  88. * specified class, when the permission is resolved.
  89. *
  90. * @param type the class name of the Permission class that will be
  91. * created when this unresolved permission is resolved.
  92. * @param name the name of the permission.
  93. * @param actions the actions of the permission.
  94. * @param certs the certificates the permission's class was signed with.
  95. * This is a list of certificate chains, where each chain is composed of a
  96. * signer certificate and optionally its supporting certificate chain.
  97. * Each chain is ordered bottom-to-top (i.e., with the signer certificate
  98. * first and the (root) certificate authority last).
  99. */
  100. public UnresolvedPermission(String type,
  101. String name,
  102. String actions,
  103. java.security.cert.Certificate certs[])
  104. {
  105. super(type);
  106. if (type == null)
  107. throw new NullPointerException("type can't be null");
  108. this.type = type;
  109. this.name = name;
  110. this.actions = actions;
  111. if (certs != null) {
  112. // Extract the signer certs from the list of certificates.
  113. for (int i=0; i<certs.length; i++) {
  114. if (!(certs[i] instanceof X509Certificate)) {
  115. // there is no concept of signer certs, so we store the
  116. // entire cert array
  117. this.certs =
  118. (java.security.cert.Certificate[])certs.clone();
  119. break;
  120. }
  121. }
  122. if (this.certs == null) {
  123. // Go through the list of certs and see if all the certs are
  124. // signer certs.
  125. int i = 0;
  126. int count = 0;
  127. while (i < certs.length) {
  128. count++;
  129. while (((i+1) < certs.length) &&
  130. ((X509Certificate)certs[i]).getIssuerDN().equals(
  131. ((X509Certificate)certs[i+1]).getSubjectDN())) {
  132. i++;
  133. }
  134. i++;
  135. }
  136. if (count == certs.length) {
  137. // All the certs are signer certs, so we store the entire
  138. // array
  139. this.certs =
  140. (java.security.cert.Certificate[])certs.clone();
  141. }
  142. if (this.certs == null) {
  143. // extract the signer certs
  144. ArrayList signerCerts = new ArrayList();
  145. i = 0;
  146. while (i < certs.length) {
  147. signerCerts.add(certs[i]);
  148. while (((i+1) < certs.length) &&
  149. ((X509Certificate)certs[i]).getIssuerDN().equals(
  150. ((X509Certificate)certs[i+1]).getSubjectDN())) {
  151. i++;
  152. }
  153. i++;
  154. }
  155. this.certs =
  156. new java.security.cert.Certificate[signerCerts.size()];
  157. signerCerts.toArray(this.certs);
  158. }
  159. }
  160. }
  161. }
  162. private static final Class[] PARAMS = { String.class, String.class};
  163. /**
  164. * try and resolve this permission using the class loader of the permission
  165. * that was passed in.
  166. */
  167. Permission resolve(Permission p, java.security.cert.Certificate certs[]) {
  168. if (this.certs != null) {
  169. // if p wasn't signed, we don't have a match
  170. if (certs == null) {
  171. return null;
  172. }
  173. // all certs in this.certs must be present in certs
  174. boolean match;
  175. for (int i = 0; i < this.certs.length; i++) {
  176. match = false;
  177. for (int j = 0; j < certs.length; j++) {
  178. if (this.certs[i].equals(certs[j])) {
  179. match = true;
  180. break;
  181. }
  182. }
  183. if (!match) return null;
  184. }
  185. }
  186. try {
  187. Class pc = p.getClass();
  188. Constructor c = pc.getConstructor(PARAMS);
  189. return (Permission) c.newInstance(new Object[] { name, actions });
  190. } catch (Exception e) {
  191. return null;
  192. }
  193. }
  194. /**
  195. * This method always returns false for unresolved permissions.
  196. * That is, an UnresolvedPermission is never considered to
  197. * imply another permission.
  198. *
  199. * @param p the permission to check against.
  200. *
  201. * @return false.
  202. */
  203. public boolean implies(Permission p) {
  204. return false;
  205. }
  206. /**
  207. * Checks two UnresolvedPermission objects for equality.
  208. * Checks that <i>obj</i> is an UnresolvedPermission, and has
  209. * the same type (class) name, permission name, actions, and
  210. * certificates as this object.
  211. *
  212. * @param obj the object we are testing for equality with this object.
  213. *
  214. * @return true if obj is an UnresolvedPermission, and has the same
  215. * type (class) name, permission name, actions, and
  216. * certificates as this object.
  217. */
  218. public boolean equals(Object obj) {
  219. if (obj == this)
  220. return true;
  221. if (! (obj instanceof UnresolvedPermission))
  222. return false;
  223. UnresolvedPermission that = (UnresolvedPermission) obj;
  224. if (!(this.type.equals(that.type) &&
  225. this.name.equals(that.name) &&
  226. this.actions.equals(that.actions)))
  227. return false;
  228. if (this.certs.length != that.certs.length)
  229. return false;
  230. int i,j;
  231. boolean match;
  232. for (i = 0; i < this.certs.length; i++) {
  233. match = false;
  234. for (j = 0; j < that.certs.length; j++) {
  235. if (this.certs[i].equals(that.certs[j])) {
  236. match = true;
  237. break;
  238. }
  239. }
  240. if (!match) return false;
  241. }
  242. for (i = 0; i < that.certs.length; i++) {
  243. match = false;
  244. for (j = 0; j < this.certs.length; j++) {
  245. if (that.certs[i].equals(this.certs[j])) {
  246. match = true;
  247. break;
  248. }
  249. }
  250. if (!match) return false;
  251. }
  252. return true;
  253. }
  254. /**
  255. * Returns the hash code value for this object.
  256. *
  257. * @return a hash code value for this object.
  258. */
  259. public int hashCode() {
  260. int hash = type.hashCode();
  261. if (name != null)
  262. hash ^= name.hashCode();
  263. if (actions != null)
  264. hash ^= actions.hashCode();
  265. return hash;
  266. }
  267. /**
  268. * Returns the canonical string representation of the actions,
  269. * which currently is the empty string "", since there are no actions for
  270. * an UnresolvedPermission. That is, the actions for the
  271. * permission that will be created when this UnresolvedPermission
  272. * is resolved may be non-null, but an UnresolvedPermission
  273. * itself is never considered to have any actions.
  274. *
  275. * @return the empty string "".
  276. */
  277. public String getActions()
  278. {
  279. return "";
  280. }
  281. /**
  282. * Returns a string describing this UnresolvedPermission. The convention
  283. * is to specify the class name, the permission name, and the actions, in
  284. * the following format: '(unresolved "ClassName" "name" "actions")'.
  285. *
  286. * @return information about this UnresolvedPermission.
  287. */
  288. public String toString() {
  289. return "(unresolved " + type + " " + name + " " + actions + ")";
  290. }
  291. /**
  292. * Returns a new PermissionCollection object for storing
  293. * UnresolvedPermission objects.
  294. * <p>
  295. * @return a new PermissionCollection object suitable for
  296. * storing UnresolvedPermissions.
  297. */
  298. public PermissionCollection newPermissionCollection() {
  299. return new UnresolvedPermissionCollection();
  300. }
  301. /**
  302. * Writes this object out to a stream (i.e., serializes it).
  303. *
  304. * @serialData An initial <code>String</code> denoting the
  305. * <code>type</code> is followed by a <code>String</code> denoting the
  306. * <code>name</code> is followed by a <code>String</code> denoting the
  307. * <code>actions</code> is followed by an <code>int</code> indicating the
  308. * number of certificates to follow
  309. * (a value of "zero" denotes that there are no certificates associated
  310. * with this object).
  311. * Each certificate is written out starting with a <code>String</code>
  312. * denoting the certificate type, followed by an
  313. * <code>int</code> specifying the length of the certificate encoding,
  314. * followed by the certificate encoding itself which is written out as an
  315. * array of bytes.
  316. */
  317. private synchronized void writeObject(java.io.ObjectOutputStream oos)
  318. throws IOException
  319. {
  320. oos.defaultWriteObject();
  321. if (certs==null || certs.length==0) {
  322. oos.writeInt(0);
  323. } else {
  324. // write out the total number of certs
  325. oos.writeInt(certs.length);
  326. // write out each cert, including its type
  327. for (int i=0; i < certs.length; i++) {
  328. java.security.cert.Certificate cert = certs[i];
  329. try {
  330. oos.writeUTF(cert.getType());
  331. byte[] encoded = cert.getEncoded();
  332. oos.writeInt(encoded.length);
  333. oos.write(encoded);
  334. } catch (CertificateEncodingException cee) {
  335. throw new IOException(cee.getMessage());
  336. }
  337. }
  338. }
  339. }
  340. /**
  341. * Restores this object from a stream (i.e., deserializes it).
  342. */
  343. private synchronized void readObject(java.io.ObjectInputStream ois)
  344. throws IOException, ClassNotFoundException
  345. {
  346. CertificateFactory cf;
  347. Hashtable cfs=null;
  348. ois.defaultReadObject();
  349. if (type == null)
  350. throw new NullPointerException("type can't be null");
  351. // process any new-style certs in the stream (if present)
  352. int size = ois.readInt();
  353. if (size > 0) {
  354. // we know of 3 different cert types: X.509, PGP, SDSI, which
  355. // could all be present in the stream at the same time
  356. cfs = new Hashtable(3);
  357. this.certs = new java.security.cert.Certificate[size];
  358. }
  359. for (int i=0; i<size; i++) {
  360. // read the certificate type, and instantiate a certificate
  361. // factory of that type (reuse existing factory if possible)
  362. String certType = ois.readUTF();
  363. if (cfs.containsKey(certType)) {
  364. // reuse certificate factory
  365. cf = (CertificateFactory)cfs.get(certType);
  366. } else {
  367. // create new certificate factory
  368. try {
  369. cf = CertificateFactory.getInstance(certType);
  370. } catch (CertificateException ce) {
  371. throw new ClassNotFoundException
  372. ("Certificate factory for "+certType+" not found");
  373. }
  374. // store the certificate factory so we can reuse it later
  375. cfs.put(certType, cf);
  376. }
  377. // parse the certificate
  378. byte[] encoded=null;
  379. try {
  380. encoded = new byte[ois.readInt()];
  381. } catch (OutOfMemoryError oome) {
  382. throw new IOException("Certificate too big");
  383. }
  384. ois.readFully(encoded);
  385. ByteArrayInputStream bais = new ByteArrayInputStream(encoded);
  386. try {
  387. this.certs[i] = cf.generateCertificate(bais);
  388. } catch (CertificateException ce) {
  389. throw new IOException(ce.getMessage());
  390. }
  391. bais.close();
  392. }
  393. }
  394. }