1. /*
  2. * Copyright 2002 Sun Microsystems, Inc. All rights reserved.
  3. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  4. */
  5. package javax.security.auth;
  6. import java.util.*;
  7. import java.security.Permission;
  8. import java.security.PermissionCollection;
  9. import java.security.Principal;
  10. /**
  11. * This class is used to protect access to private Credentials
  12. * belonging to a particular <code>Subject</code>. The <code>Subject</code>
  13. * is represented by a Set of Principals.
  14. *
  15. * <p> The target name of this <code>Permission</code> specifies
  16. * a Credential class name, and a Set of Principals.
  17. * The only valid value for this Permission's actions is, "read".
  18. * The target name must abide by the following syntax:
  19. *
  20. * <pre>
  21. * CredentialClass {PrincipalClass "PrincipalName"}*
  22. * </pre>
  23. *
  24. * For example, the following permission grants access to the
  25. * com.sun.PrivateCredential owned by Subjects which have
  26. * a com.sun.Principal with the name, "duke". Note that although
  27. * this example, as well as all the examples below, do not contain
  28. * Codebase, SignedBy, or Principal information in the grant statement
  29. * (for simplicity reasons), actual policy configurations should
  30. * specify that information when appropriate.
  31. *
  32. * <pre>
  33. *
  34. * grant {
  35. * permission javax.security.auth.PrivateCredentialPermission
  36. * "com.sun.PrivateCredential com.sun.Principal \"duke\"",
  37. * "read";
  38. * };
  39. * </pre>
  40. *
  41. * If CredentialClass is "*", then access is granted to
  42. * all private Credentials belonging to the specified
  43. * <code>Subject</code>.
  44. * If "PrincipalName" is "*", then access is granted to the
  45. * specified Credential owned by any <code>Subject</code> that has the
  46. * specified <code>Principal</code> (the actual PrincipalName doesn't matter).
  47. * For example, the following grants access to the
  48. * a.b.Credential owned by any <code>Subject</code> that has
  49. * an a.b.Principal.
  50. *
  51. * <pre>
  52. * grant {
  53. * permission javax.security.auth.PrivateCredentialPermission
  54. * "a.b.Credential a.b.Principal "*"",
  55. * "read";
  56. * };
  57. * </pre>
  58. *
  59. * If both the PrincipalClass and "PrincipalName" are "*",
  60. * then access is granted to the specified Credential owned by
  61. * any <code>Subject</code>.
  62. *
  63. * <p> In addition, the PrincipalClass/PrincipalName pairing may be repeated:
  64. *
  65. * <pre>
  66. * grant {
  67. * permission javax.security.auth.PrivateCredentialPermission
  68. * "a.b.Credential a.b.Principal "duke" c.d.Principal "dukette"",
  69. * "read";
  70. * };
  71. * </pre>
  72. *
  73. * The above grants access to the private Credential, "a.b.Credential",
  74. * belonging to a <code>Subject</code> with at least two associated Principals:
  75. * "a.b.Principal" with the name, "duke", and "c.d.Principal", with the name,
  76. * "dukette".
  77. *
  78. * @version 1.16, 01/19/00
  79. */
  80. public final class PrivateCredentialPermission extends Permission {
  81. private static final java.util.ResourceBundle rb =
  82. java.util.ResourceBundle.getBundle("com.sun.security.auth.Resources");
  83. /**
  84. * @serial
  85. */
  86. private String credentialClass;
  87. /**
  88. * @serial
  89. */
  90. private Set principals;
  91. /**
  92. * @serial
  93. */
  94. private boolean testing = false;
  95. private static void main(String args[]) {
  96. LinkedList list = new LinkedList();
  97. PrivateCredentialPermission pcp = new PrivateCredentialPermission
  98. ("a.b.c d.e.f \"charlie\"", "read");
  99. list.add(pcp);
  100. pcp = new PrivateCredentialPermission
  101. ("a.b.c a \"lai\" d.e.f \"charlie\"", "read");
  102. System.out.println("pcp.credentialClass = " + pcp.getCredentialClass());
  103. String[][] pArray = pcp.getPrincipals();
  104. for (int i = 0; i < pArray.length; i++) {
  105. for (int j = 0; j < 2; j++) {
  106. System.out.println("pArray[" + i + "][" + j + "] = " +
  107. pArray[i][j]);
  108. }
  109. }
  110. list.add(pcp);
  111. for (int i = 0; i < args.length; i++) {
  112. pcp = new PrivateCredentialPermission(args[i], "read");
  113. list.add(pcp);
  114. }
  115. if ((list.size() % 2) != 0) {
  116. pcp = new PrivateCredentialPermission
  117. (" none none \"none\"", "read");
  118. list.add(pcp);
  119. }
  120. ListIterator li = list.listIterator(0);
  121. while (li.hasNext()) {
  122. PrivateCredentialPermission p1 =
  123. (PrivateCredentialPermission)li.next();
  124. PrivateCredentialPermission p2 =
  125. (PrivateCredentialPermission)li.next();
  126. System.out.println("p1.implies(p2): " + p1.implies(p2));
  127. }
  128. }
  129. /**
  130. * Convenience function to create a PrivateCredentialPermission
  131. * from a Credential class String and a Set of Permissions.
  132. */
  133. static String buildTarget(String credentialClass, Set principals) {
  134. if (credentialClass == null ||
  135. principals == null ||
  136. principals.size() == 0)
  137. throw new IllegalArgumentException
  138. (rb.getString("invalid null input(s)"));
  139. String name = credentialClass;
  140. Iterator i = principals.iterator();
  141. while (i.hasNext()) {
  142. Principal p = (Principal)i.next();
  143. name += " " + p.getClass().getName() + " \"" + p.getName() + "\"";
  144. }
  145. return name;
  146. }
  147. Set getPrincipalSet() {
  148. return principals;
  149. }
  150. /**
  151. * Create a new <code>PrivateCredentialPermission</code>
  152. * with the specified <code>credentialClass</code>
  153. * and an empty set of Principals.
  154. */
  155. PrivateCredentialPermission(String credentialClass, Set principals) {
  156. super(credentialClass);
  157. this.credentialClass = credentialClass;
  158. this.principals = principals;
  159. }
  160. /**
  161. * Creates a new <code>PrivateCredentialPermission</code>
  162. * with the specified <code>name</code>. The <code>name</code>
  163. * specifies both a Credential class and a <code>Principal</code> Set.
  164. *
  165. * <p>
  166. *
  167. * @param name the name specifying the Credential class and
  168. * <code>Principal</code> Set. <p>
  169. *
  170. * @param actions the actions specifying that the Credential can be read.
  171. *
  172. * @throw IllegalArgumentException if <code>name</code> does not conform
  173. * to the correct syntax or if <code>actions</code> is not "read".
  174. */
  175. public PrivateCredentialPermission(String name, String actions) {
  176. super(name);
  177. if (!"read".equalsIgnoreCase(actions))
  178. throw new IllegalArgumentException
  179. (rb.getString("actions can only be 'read'"));
  180. init(name);
  181. }
  182. /**
  183. * Returns the Class name of the Credential associated with this
  184. * <code>PrivateCredentialPermission</code>.
  185. *
  186. * <p>
  187. *
  188. * @return the Class name of the Credential associated with this
  189. * <code>PrivateCredentialPermission</code>.
  190. */
  191. public String getCredentialClass() {
  192. return credentialClass;
  193. }
  194. /**
  195. * Returns the <code>Principal</code> classes and names
  196. * associated with this <code>PrivateCredentialPermission</code>.
  197. * The information is returned as a two-dimensional array (array[x][y]).
  198. * The 'x' value corresponds to the number of <code>Principal</code>
  199. * class and name pairs. When (y==0), it corresponds to
  200. * the <code>Principal</code> class value, and when (y==1),
  201. * it corresponds to the <code>Principal</code> name value.
  202. * For example, array[0][0] corresponds to the class name of
  203. * the first <code>Principal</code> in the array. array[0][1]
  204. * corresponds to the <code>Principal</code> name of the
  205. * first <code>Principal</code> in the array.
  206. *
  207. * <p>
  208. *
  209. * @return the <code>Principal</code> class and names associated
  210. * with this <code>PrivateCredentialPermission</code>.
  211. */
  212. public String[][] getPrincipals() {
  213. if (principals == null) {
  214. // this should never happen
  215. return new String[0][0];
  216. }
  217. String[][] pArray = new String[principals.size()][2];
  218. Iterator pIterator = principals.iterator();
  219. int i = 0;
  220. while (pIterator.hasNext()) {
  221. CredOwner co = (CredOwner)pIterator.next();
  222. pArray[i][0] = co.principalClass;
  223. pArray[i][1] = co.principalName;
  224. i++;
  225. }
  226. return pArray;
  227. }
  228. /**
  229. * Checks if this <code>PrivateCredentialPermission</code> implies
  230. * the specified <code>Permission</code>.
  231. *
  232. * <p>
  233. *
  234. * This method returns true if:
  235. * <p><ul>
  236. * <li> <i>p</i> is an instanceof PrivateCredentialPermission and <p>
  237. * <li> the target name for <i>p</i> is implied by this object's
  238. * target name. For example:
  239. * <pre>
  240. * [* P1 "duke"] implies [a.b.Credential P1 "duke"].
  241. * [C1 P1 "duke"] implies [C1 P1 "duke" P2 "dukette"].
  242. * [C1 P2 "dukette"] implies [C1 P1 "duke" P2 "dukette"].
  243. * </pre>
  244. * </ul>
  245. *
  246. * <p>
  247. *
  248. * @param p the <code>Permission</code> to check against.
  249. */
  250. public boolean implies(Permission p) {
  251. if (p == null || !(p instanceof PrivateCredentialPermission))
  252. return false;
  253. PrivateCredentialPermission that = (PrivateCredentialPermission)p;
  254. if (!impliesCredentialClass(credentialClass, that.getCredentialClass()))
  255. return false;
  256. return impliesPrincipalSet(principals, that.getPrincipalSet());
  257. }
  258. /**
  259. * Checks two <code>PrivateCredentialPermission</code> objects for
  260. * equality. Checks that <i>obj</i> is a
  261. * <code>PrivateCredentialPermission</code>,
  262. * and has the same target name as this object.
  263. *
  264. * <p>
  265. *
  266. * @param obj the object we are testing for equality with this object.
  267. *
  268. * @return true if obj is a <code>PrivateCredentialPermission</code>,
  269. * and has the same target name.
  270. */
  271. public boolean equals(Object obj) {
  272. if (obj == this)
  273. return true;
  274. if (! (obj instanceof PrivateCredentialPermission))
  275. return false;
  276. PrivateCredentialPermission that = (PrivateCredentialPermission) obj;
  277. return (this.getName().equalsIgnoreCase(that.getName()));
  278. }
  279. /**
  280. * Returns the hash code value for this object.
  281. *
  282. * @return a hash code value for this object.
  283. */
  284. public int hashCode() {
  285. return this.getName().hashCode();
  286. }
  287. /**
  288. * Returns the "canonical string representation" of the actions.
  289. * This method always returns the String, "read".
  290. *
  291. * <p>
  292. *
  293. * @return the actions (always returns "read").
  294. */
  295. public String getActions() {
  296. return "read";
  297. }
  298. /**
  299. * Return a homogeneous collection of PrivateCredentialPermissions
  300. * in a <code>PermissionCollection</code>.
  301. * No such <code>PermissionCollection</code> is defined,
  302. * so this method always returns <code>null</code>.
  303. *
  304. * <p>
  305. *
  306. * @return null in all cases.
  307. */
  308. public PermissionCollection newPermissionCollection() {
  309. return null;
  310. }
  311. private void init(String name) {
  312. principals = new HashSet();
  313. StringTokenizer tokenizer = new StringTokenizer(name, " ", false);
  314. String principalClass = null;
  315. String principalName = null;
  316. if (testing)
  317. System.out.println("whole name = " + name);
  318. // get the Credential Class
  319. credentialClass = tokenizer.nextToken();
  320. if (testing)
  321. System.out.println("Credential Class = " + credentialClass);
  322. if (tokenizer.hasMoreTokens() == false)
  323. throw new IllegalArgumentException
  324. (rb.getString("permission name [") +
  325. name +
  326. rb.getString("] syntax invalid: ") +
  327. rb.getString("Credential Class not followed by a ") +
  328. rb.getString("Principal Class and Name"));
  329. while (tokenizer.hasMoreTokens()) {
  330. // get the Principal Class
  331. principalClass = tokenizer.nextToken();
  332. if (testing)
  333. System.out.println(" Principal Class = " + principalClass);
  334. if (tokenizer.hasMoreTokens() == false)
  335. throw new IllegalArgumentException
  336. (rb.getString("permission name [") +
  337. name +
  338. rb.getString("] syntax invalid: ") +
  339. rb.getString("Principal Class not followed by a ") +
  340. rb.getString("Principal Name"));
  341. // get the Principal Name
  342. principalName = tokenizer.nextToken();
  343. if (!principalName.startsWith("\"")) {
  344. throw new IllegalArgumentException
  345. (rb.getString("permission name [") +
  346. name +
  347. rb.getString("] syntax invalid: ") +
  348. rb.getString("Principal Name must be surrounded by quotes"));
  349. }
  350. if (!principalName.endsWith("\"")) {
  351. // we have a name with spaces in it --
  352. // keep parsing until we find the end quote
  353. while (tokenizer.hasMoreTokens()) {
  354. principalName = principalName + " " + tokenizer.nextToken();
  355. if (principalName.endsWith("\""))
  356. break;
  357. }
  358. if (!principalName.endsWith("\"")) {
  359. throw new IllegalArgumentException
  360. (rb.getString("permission name [") +
  361. name +
  362. rb.getString("] syntax invalid: ") +
  363. rb.getString("Principal Name missing end quote"));
  364. }
  365. }
  366. if (testing)
  367. System.out.println("\tprincipalName = '" + principalName + "'");
  368. principalName = principalName.substring
  369. (1, principalName.length() - 1);
  370. if (principalClass.equals("*") &&
  371. !principalName.equals("*")) {
  372. throw new IllegalArgumentException
  373. (rb.getString("PrivateCredentialPermission ") +
  374. rb.getString("Principal Class can not be a ") +
  375. rb.getString("wildcard (*) value if Principal Name ") +
  376. rb.getString("is not a wildcard (*) value"));
  377. }
  378. if (testing)
  379. System.out.println("\tprincipalName = '" + principalName + "'");
  380. CredOwner co = new CredOwner(principalClass, principalName);
  381. principals.add(co);
  382. }
  383. }
  384. private boolean impliesCredentialClass(String thisC, String thatC) {
  385. // this should never happen
  386. if (thisC == null || thatC == null)
  387. return false;
  388. if (testing)
  389. System.out.println("credential class comparison: " +
  390. thisC + "/" + thatC);
  391. if (thisC.equals("*"))
  392. return true;
  393. /**
  394. * XXX let's not enable this for now --
  395. * if people want it, we'll enable it later
  396. */
  397. /*
  398. if (thisC.endsWith("*")) {
  399. String cClass = thisC.substring(0, thisC.length() - 2);
  400. return thatC.startsWith(cClass);
  401. }
  402. */
  403. return thisC.equals(thatC);
  404. }
  405. private boolean impliesPrincipalSet(Set thisP, Set thatP) {
  406. // this should never happen
  407. if (thisP == null || thatP == null)
  408. return false;
  409. if (testing) {
  410. Iterator i = thisP.iterator();
  411. for (int j = 0; j < thisP.size(); j++) {
  412. CredOwner co = (CredOwner)i.next();
  413. System.out.println("this permission set [" + j + "]= " +
  414. co.toString());
  415. }
  416. }
  417. if (thatP.size() == 0)
  418. return true;
  419. if (thisP.size() == 0)
  420. return false;
  421. // make sure thatP "contains all" of the principals in thisP
  422. //
  423. // XXX we can not simply call containsAll on the sets
  424. // because we're not doing an "equals" --
  425. // we're doing an "implies"
  426. Iterator thisI = thisP.iterator();
  427. while (thisI.hasNext()) {
  428. CredOwner thisOwner = (CredOwner)thisI.next();
  429. Iterator thatI = thatP.iterator();
  430. boolean foundMatch = false;
  431. while (thatI.hasNext()) {
  432. CredOwner thatOwner = (CredOwner)thatI.next();
  433. if (thisOwner.implies(thatOwner)) {
  434. foundMatch = true;
  435. break;
  436. }
  437. }
  438. if (!foundMatch)
  439. return false;
  440. }
  441. return true;
  442. }
  443. class CredOwner implements java.io.Serializable {
  444. /**
  445. * @serial
  446. */
  447. String principalClass;
  448. /**
  449. * @serial
  450. */
  451. String principalName;
  452. CredOwner(String principalClass, String principalName) {
  453. this.principalClass = principalClass;
  454. this.principalName = principalName;
  455. }
  456. public boolean implies(Object obj) {
  457. if (obj == null || !(obj instanceof CredOwner))
  458. return false;
  459. CredOwner that = (CredOwner)obj;
  460. if (PrivateCredentialPermission.this.testing == true) {
  461. System.out.println("principal comparison:\n\t" +
  462. principalClass + "/" + that.principalClass + "\n\t" +
  463. principalName + "/" + that.principalName);
  464. }
  465. if (principalClass.equals("*") ||
  466. principalClass.equals(that.principalClass)) {
  467. if (principalName.equals("*") ||
  468. principalName.equals(that.principalName)) {
  469. return true;
  470. }
  471. }
  472. /**
  473. * XXX no code yet to support a.b.*
  474. */
  475. return false;
  476. }
  477. public String toString() {
  478. return rb.getString("CredOwner:\n\t") +
  479. rb.getString("Principal Class = ") +
  480. principalClass +
  481. rb.getString("\n\t") +
  482. rb.getString("Principal Name = ") +
  483. principalName;
  484. }
  485. }
  486. }