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