1. /*
  2. * @(#)UnresolvedPermission.java 1.24 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.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.
  51. *
  52. * <p> To instantiate the new class, UnresolvedPermission assumes
  53. * the class provides a zero, one, and/or two-argument constructor.
  54. * The zero-argument constructor would be used to instantiate
  55. * a permission without a name and without actions.
  56. * A one-arg constructor is assumed to take a <code>String</code>
  57. * name as input, and a two-arg constructor is assumed to take a
  58. * <code>String</code> name and <code>String</code> actions
  59. * as input. UnresolvedPermission may invoke a
  60. * constructor with a <code>null</code> name and/or actions.
  61. * If an appropriate permission constructor is not available,
  62. * the UnresolvedPermission is ignored and the relevant permission
  63. * will not be granted to executing code.
  64. *
  65. * <p> The newly created permission object replaces the
  66. * UnresolvedPermission, which is removed.
  67. *
  68. * @see java.security.Permission
  69. * @see java.security.Permissions
  70. * @see java.security.PermissionCollection
  71. * @see java.security.Policy
  72. *
  73. * @version 1.24 03/01/23
  74. *
  75. * @author Roland Schemers
  76. */
  77. public final class UnresolvedPermission extends Permission
  78. implements java.io.Serializable
  79. {
  80. private static final sun.security.util.Debug debug =
  81. sun.security.util.Debug.getInstance
  82. ("policy,access", "UnresolvedPermission");
  83. /**
  84. * The class name of the Permission class that will be
  85. * created when this unresolved permission is resolved.
  86. *
  87. * @serial
  88. */
  89. private String type;
  90. /**
  91. * The permission name.
  92. *
  93. * @serial
  94. */
  95. private String name;
  96. /**
  97. * The actions of the permission.
  98. *
  99. * @serial
  100. */
  101. private String actions;
  102. private transient java.security.cert.Certificate certs[];
  103. /**
  104. * Creates a new UnresolvedPermission containing the permission
  105. * information needed later to actually create a Permission of the
  106. * specified class, when the permission is resolved.
  107. *
  108. * @param type the class name of the Permission class that will be
  109. * created when this unresolved permission is resolved.
  110. * @param name the name of the permission.
  111. * @param actions the actions of the permission.
  112. * @param certs the certificates the permission's class was signed with.
  113. * This is a list of certificate chains, where each chain is composed of a
  114. * signer certificate and optionally its supporting certificate chain.
  115. * Each chain is ordered bottom-to-top (i.e., with the signer certificate
  116. * first and the (root) certificate authority last).
  117. */
  118. public UnresolvedPermission(String type,
  119. String name,
  120. String actions,
  121. java.security.cert.Certificate certs[])
  122. {
  123. super(type);
  124. if (type == null)
  125. throw new NullPointerException("type can't be null");
  126. this.type = type;
  127. this.name = name;
  128. this.actions = actions;
  129. if (certs != null) {
  130. // Extract the signer certs from the list of certificates.
  131. for (int i=0; i<certs.length; i++) {
  132. if (!(certs[i] instanceof X509Certificate)) {
  133. // there is no concept of signer certs, so we store the
  134. // entire cert array
  135. this.certs =
  136. (java.security.cert.Certificate[])certs.clone();
  137. break;
  138. }
  139. }
  140. if (this.certs == null) {
  141. // Go through the list of certs and see if all the certs are
  142. // signer certs.
  143. int i = 0;
  144. int count = 0;
  145. while (i < certs.length) {
  146. count++;
  147. while (((i+1) < certs.length) &&
  148. ((X509Certificate)certs[i]).getIssuerDN().equals(
  149. ((X509Certificate)certs[i+1]).getSubjectDN())) {
  150. i++;
  151. }
  152. i++;
  153. }
  154. if (count == certs.length) {
  155. // All the certs are signer certs, so we store the entire
  156. // array
  157. this.certs =
  158. (java.security.cert.Certificate[])certs.clone();
  159. }
  160. if (this.certs == null) {
  161. // extract the signer certs
  162. ArrayList signerCerts = new ArrayList();
  163. i = 0;
  164. while (i < certs.length) {
  165. signerCerts.add(certs[i]);
  166. while (((i+1) < certs.length) &&
  167. ((X509Certificate)certs[i]).getIssuerDN().equals(
  168. ((X509Certificate)certs[i+1]).getSubjectDN())) {
  169. i++;
  170. }
  171. i++;
  172. }
  173. this.certs =
  174. new java.security.cert.Certificate[signerCerts.size()];
  175. signerCerts.toArray(this.certs);
  176. }
  177. }
  178. }
  179. }
  180. private static final Class[] PARAMS0 = { };
  181. private static final Class[] PARAMS1 = { String.class };
  182. private static final Class[] PARAMS2 = { String.class, String.class };
  183. /**
  184. * try and resolve this permission using the class loader of the permission
  185. * that was passed in.
  186. */
  187. Permission resolve(Permission p, java.security.cert.Certificate certs[]) {
  188. if (this.certs != null) {
  189. // if p wasn't signed, we don't have a match
  190. if (certs == null) {
  191. return null;
  192. }
  193. // all certs in this.certs must be present in certs
  194. boolean match;
  195. for (int i = 0; i < this.certs.length; i++) {
  196. match = false;
  197. for (int j = 0; j < certs.length; j++) {
  198. if (this.certs[i].equals(certs[j])) {
  199. match = true;
  200. break;
  201. }
  202. }
  203. if (!match) return null;
  204. }
  205. }
  206. try {
  207. Class pc = p.getClass();
  208. if (name == null && actions == null) {
  209. try {
  210. Constructor c = pc.getConstructor(PARAMS0);
  211. return (Permission)c.newInstance(new Object[] {});
  212. } catch (NoSuchMethodException ne) {
  213. try {
  214. Constructor c = pc.getConstructor(PARAMS1);
  215. return (Permission) c.newInstance(
  216. new Object[] { name});
  217. } catch (NoSuchMethodException ne1) {
  218. Constructor c = pc.getConstructor(PARAMS2);
  219. return (Permission) c.newInstance(
  220. new Object[] { name, actions });
  221. }
  222. }
  223. } else {
  224. if (name != null && actions == null) {
  225. try {
  226. Constructor c = pc.getConstructor(PARAMS1);
  227. return (Permission) c.newInstance(
  228. new Object[] { name});
  229. } catch (NoSuchMethodException ne) {
  230. Constructor c = pc.getConstructor(PARAMS2);
  231. return (Permission) c.newInstance(
  232. new Object[] { name, actions });
  233. }
  234. } else {
  235. Constructor c = pc.getConstructor(PARAMS2);
  236. return (Permission) c.newInstance(
  237. new Object[] { name, actions });
  238. }
  239. }
  240. } catch (NoSuchMethodException nsme) {
  241. if (debug != null ) {
  242. debug.println("NoSuchMethodException:\n could not find " +
  243. "proper constructor for " + type);
  244. nsme.printStackTrace();
  245. }
  246. return null;
  247. } catch (Exception e) {
  248. if (debug != null ) {
  249. debug.println("unable to instantiate " + name);
  250. e.printStackTrace();
  251. }
  252. return null;
  253. }
  254. }
  255. /**
  256. * This method always returns false for unresolved permissions.
  257. * That is, an UnresolvedPermission is never considered to
  258. * imply another permission.
  259. *
  260. * @param p the permission to check against.
  261. *
  262. * @return false.
  263. */
  264. public boolean implies(Permission p) {
  265. return false;
  266. }
  267. /**
  268. * Checks two UnresolvedPermission objects for equality.
  269. * Checks that <i>obj</i> is an UnresolvedPermission, and has
  270. * the same type (class) name, permission name, actions, and
  271. * certificates as this object.
  272. *
  273. * @param obj the object we are testing for equality with this object.
  274. *
  275. * @return true if obj is an UnresolvedPermission, and has the same
  276. * type (class) name, permission name, actions, and
  277. * certificates as this object.
  278. */
  279. public boolean equals(Object obj) {
  280. if (obj == this)
  281. return true;
  282. if (! (obj instanceof UnresolvedPermission))
  283. return false;
  284. UnresolvedPermission that = (UnresolvedPermission) obj;
  285. // check type
  286. if (!this.type.equals(that.type)) {
  287. return false;
  288. }
  289. // check name
  290. if (this.name == null) {
  291. if (that.name != null) {
  292. return false;
  293. }
  294. } else if (!this.name.equals(that.name)) {
  295. return false;
  296. }
  297. // check actions
  298. if (this.actions == null) {
  299. if (that.actions != null) {
  300. return false;
  301. }
  302. } else {
  303. if (!this.actions.equals(that.actions)) {
  304. return false;
  305. }
  306. }
  307. // check certs
  308. if ((this.certs == null && that.certs != null) ||
  309. (this.certs != null && that.certs == null) ||
  310. (this.certs != null && that.certs != null &&
  311. this.certs.length != that.certs.length)) {
  312. return false;
  313. }
  314. int i,j;
  315. boolean match;
  316. for (i = 0; this.certs != null && i < this.certs.length; i++) {
  317. match = false;
  318. for (j = 0; j < that.certs.length; j++) {
  319. if (this.certs[i].equals(that.certs[j])) {
  320. match = true;
  321. break;
  322. }
  323. }
  324. if (!match) return false;
  325. }
  326. for (i = 0; that.certs != null && i < that.certs.length; i++) {
  327. match = false;
  328. for (j = 0; j < this.certs.length; j++) {
  329. if (that.certs[i].equals(this.certs[j])) {
  330. match = true;
  331. break;
  332. }
  333. }
  334. if (!match) return false;
  335. }
  336. return true;
  337. }
  338. /**
  339. * Returns the hash code value for this object.
  340. *
  341. * @return a hash code value for this object.
  342. */
  343. public int hashCode() {
  344. int hash = type.hashCode();
  345. if (name != null)
  346. hash ^= name.hashCode();
  347. if (actions != null)
  348. hash ^= actions.hashCode();
  349. return hash;
  350. }
  351. /**
  352. * Returns the canonical string representation of the actions,
  353. * which currently is the empty string "", since there are no actions for
  354. * an UnresolvedPermission. That is, the actions for the
  355. * permission that will be created when this UnresolvedPermission
  356. * is resolved may be non-null, but an UnresolvedPermission
  357. * itself is never considered to have any actions.
  358. *
  359. * @return the empty string "".
  360. */
  361. public String getActions()
  362. {
  363. return "";
  364. }
  365. /**
  366. * Returns a string describing this UnresolvedPermission. The convention
  367. * is to specify the class name, the permission name, and the actions, in
  368. * the following format: '(unresolved "ClassName" "name" "actions")'.
  369. *
  370. * @return information about this UnresolvedPermission.
  371. */
  372. public String toString() {
  373. return "(unresolved " + type + " " + name + " " + actions + ")";
  374. }
  375. /**
  376. * Returns a new PermissionCollection object for storing
  377. * UnresolvedPermission objects.
  378. * <p>
  379. * @return a new PermissionCollection object suitable for
  380. * storing UnresolvedPermissions.
  381. */
  382. public PermissionCollection newPermissionCollection() {
  383. return new UnresolvedPermissionCollection();
  384. }
  385. /**
  386. * Writes this object out to a stream (i.e., serializes it).
  387. *
  388. * @serialData An initial <code>String</code> denoting the
  389. * <code>type</code> is followed by a <code>String</code> denoting the
  390. * <code>name</code> is followed by a <code>String</code> denoting the
  391. * <code>actions</code> is followed by an <code>int</code> indicating the
  392. * number of certificates to follow
  393. * (a value of "zero" denotes that there are no certificates associated
  394. * with this object).
  395. * Each certificate is written out starting with a <code>String</code>
  396. * denoting the certificate type, followed by an
  397. * <code>int</code> specifying the length of the certificate encoding,
  398. * followed by the certificate encoding itself which is written out as an
  399. * array of bytes.
  400. */
  401. private synchronized void writeObject(java.io.ObjectOutputStream oos)
  402. throws IOException
  403. {
  404. oos.defaultWriteObject();
  405. if (certs==null || certs.length==0) {
  406. oos.writeInt(0);
  407. } else {
  408. // write out the total number of certs
  409. oos.writeInt(certs.length);
  410. // write out each cert, including its type
  411. for (int i=0; i < certs.length; i++) {
  412. java.security.cert.Certificate cert = certs[i];
  413. try {
  414. oos.writeUTF(cert.getType());
  415. byte[] encoded = cert.getEncoded();
  416. oos.writeInt(encoded.length);
  417. oos.write(encoded);
  418. } catch (CertificateEncodingException cee) {
  419. throw new IOException(cee.getMessage());
  420. }
  421. }
  422. }
  423. }
  424. /**
  425. * Restores this object from a stream (i.e., deserializes it).
  426. */
  427. private synchronized void readObject(java.io.ObjectInputStream ois)
  428. throws IOException, ClassNotFoundException
  429. {
  430. CertificateFactory cf;
  431. Hashtable cfs=null;
  432. ois.defaultReadObject();
  433. if (type == null)
  434. throw new NullPointerException("type can't be null");
  435. // process any new-style certs in the stream (if present)
  436. int size = ois.readInt();
  437. if (size > 0) {
  438. // we know of 3 different cert types: X.509, PGP, SDSI, which
  439. // could all be present in the stream at the same time
  440. cfs = new Hashtable(3);
  441. this.certs = new java.security.cert.Certificate[size];
  442. }
  443. for (int i=0; i<size; i++) {
  444. // read the certificate type, and instantiate a certificate
  445. // factory of that type (reuse existing factory if possible)
  446. String certType = ois.readUTF();
  447. if (cfs.containsKey(certType)) {
  448. // reuse certificate factory
  449. cf = (CertificateFactory)cfs.get(certType);
  450. } else {
  451. // create new certificate factory
  452. try {
  453. cf = CertificateFactory.getInstance(certType);
  454. } catch (CertificateException ce) {
  455. throw new ClassNotFoundException
  456. ("Certificate factory for "+certType+" not found");
  457. }
  458. // store the certificate factory so we can reuse it later
  459. cfs.put(certType, cf);
  460. }
  461. // parse the certificate
  462. byte[] encoded=null;
  463. try {
  464. encoded = new byte[ois.readInt()];
  465. } catch (OutOfMemoryError oome) {
  466. throw new IOException("Certificate too big");
  467. }
  468. ois.readFully(encoded);
  469. ByteArrayInputStream bais = new ByteArrayInputStream(encoded);
  470. try {
  471. this.certs[i] = cf.generateCertificate(bais);
  472. } catch (CertificateException ce) {
  473. throw new IOException(ce.getMessage());
  474. }
  475. bais.close();
  476. }
  477. }
  478. }