1. /*
  2. * @(#)DelegationPermission.java 1.9 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 javax.security.auth.kerberos;
  8. import java.util.*;
  9. import java.security.Permission;
  10. import java.security.BasicPermission;
  11. import java.security.PermissionCollection;
  12. import java.io.ObjectStreamField;
  13. import java.io.ObjectOutputStream;
  14. import java.io.ObjectInputStream;
  15. import java.io.IOException;
  16. /**
  17. * This class is used to restrict the usage of the Kerberos
  18. * delegation model, ie: forwardable and proxiable tickets.
  19. * <p>
  20. * The target name of this <code>Permission</code> specifies a pair of
  21. * kerberos service principals. The first is the subordinate service principal
  22. * being entrusted to use the TGT. The second service principal designates
  23. * the target service the subordinate service principal is to
  24. * interact with on behalf of the initiating KerberosPrincipal. This
  25. * latter service principal is specified to restrict the use of a
  26. * proxiable ticket.
  27. * <p>
  28. * For example, to specify the "host" service use of a forwardable TGT the
  29. * target permission is specified as follows:
  30. * <p>
  31. * <pre>
  32. * DelegationPermission("\"host/foo.example.com@EXAMPLE.COM\" \"krbtgt/EXAMPLE.COM@EXAMPLE.COM\"");
  33. * </pre>
  34. * <p>
  35. * To give the "backup" service a proxiable nfs service ticket the target permission
  36. * might be specified:
  37. * <p>
  38. * <pre>
  39. * DelegationPermission("\"backup/bar.example.com@EXAMPLE.COM\" \"nfs/home.EXAMPLE.COM@EXAMPLE.COM\"");
  40. * </pre>
  41. *
  42. * @since JDK1.4
  43. */
  44. public final class DelegationPermission extends BasicPermission
  45. implements java.io.Serializable {
  46. private static final long serialVersionUID = 883133252142523922L;
  47. private transient String subordinate, service;
  48. /**
  49. * Create a new <code>DelegationPermission</code>
  50. * with the specified subordinate and target principals.
  51. *
  52. * <p>
  53. *
  54. * @param principals the name of the subordinate and target principals
  55. */
  56. public DelegationPermission(String principals) {
  57. super(principals);
  58. init(principals);
  59. }
  60. /**
  61. * Create a new <code>DelegationPermission</code>
  62. * with the specified subordinate and target principals.
  63. * <p>
  64. *
  65. * @param principals the name of the subordinate and target principals
  66. * <p>
  67. * @param actions should be null.
  68. */
  69. public DelegationPermission(String principals, String actions) {
  70. super(principals, actions);
  71. init(principals);
  72. }
  73. /**
  74. * Initialize the DelegationPermission object.
  75. */
  76. private void init(String target) {
  77. StringTokenizer t = null;
  78. if (!target.startsWith("\"")) {
  79. throw new IllegalArgumentException
  80. ("service principal [" + target +
  81. "] syntax invalid: " +
  82. "improperly quoted");
  83. } else {
  84. t = new StringTokenizer(target, "\"", false);
  85. subordinate = t.nextToken();
  86. if (t.countTokens() == 2) {
  87. t.nextToken(); // bypass whitespace
  88. service = t.nextToken();
  89. } else if (t.countTokens() > 0) {
  90. throw new IllegalArgumentException
  91. ("service principal [" + t.nextToken() +
  92. "] syntax invalid: " +
  93. "improperly quoted");
  94. }
  95. }
  96. }
  97. /**
  98. * Checks if this Kerberos delegation permission object "implies" the
  99. * specified permission.
  100. * <P>
  101. * If none of the above are true, <code>implies</code> returns false.
  102. * @param p the permission to check against.
  103. *
  104. * @return true if the specified permission is implied by this object,
  105. * false if not.
  106. */
  107. public boolean implies(Permission p) {
  108. if (!(p instanceof DelegationPermission))
  109. return false;
  110. DelegationPermission that = (DelegationPermission) p;
  111. if (this.subordinate.equals(that.subordinate) &&
  112. this.service.equals(that.service))
  113. return true;
  114. return false;
  115. }
  116. /**
  117. * Checks two DelegationPermission objects for equality.
  118. * <P>
  119. * @param obj the object to test for equality with this object.
  120. *
  121. * @return true if <i>obj</i> is a DelegationPermission, and
  122. * has the same subordinate and service principal as this.
  123. * DelegationPermission object.
  124. */
  125. public boolean equals(Object obj) {
  126. if (obj == this)
  127. return true;
  128. if (! (obj instanceof DelegationPermission))
  129. return false;
  130. DelegationPermission that = (DelegationPermission) obj;
  131. return implies(that);
  132. }
  133. /**
  134. * Returns the hash code value for this object.
  135. *
  136. * @return a hash code value for this object.
  137. */
  138. public int hashCode() {
  139. return getName().hashCode();
  140. }
  141. /**
  142. * Returns a PermissionCollection object for storing
  143. * DelegationPermission objects.
  144. * <br>
  145. * DelegationPermission objects must be stored in a manner that
  146. * allows them to be inserted into the collection in any order, but
  147. * that also enables the PermissionCollection implies method to
  148. * be implemented in an efficient (and consistent) manner.
  149. *
  150. * @return a new PermissionCollection object suitable for storing
  151. * DelegationPermissions.
  152. */
  153. public PermissionCollection newPermissionCollection() {
  154. return new KrbDelegationPermissionCollection();
  155. }
  156. /**
  157. * WriteObject is called to save the state of the DelegationPermission
  158. * to a stream. The actions are serialized, and the superclass
  159. * takes care of the name.
  160. */
  161. private synchronized void writeObject(java.io.ObjectOutputStream s)
  162. throws IOException
  163. {
  164. s.defaultWriteObject();
  165. }
  166. /**
  167. * readObject is called to restore the state of the
  168. * DelegationPermission from a stream.
  169. */
  170. private synchronized void readObject(java.io.ObjectInputStream s)
  171. throws IOException, ClassNotFoundException
  172. {
  173. // Read in the action, then initialize the rest
  174. s.defaultReadObject();
  175. init(getName());
  176. }
  177. /*
  178. public static void main(String args[]) throws Exception {
  179. DelegationPermission this_ =
  180. new DelegationPermission(args[0]);
  181. DelegationPermission that_ =
  182. new DelegationPermission(args[1]);
  183. System.out.println("-----\n");
  184. System.out.println("this.implies(that) = " + this_.implies(that_));
  185. System.out.println("-----\n");
  186. System.out.println("this = "+this_);
  187. System.out.println("-----\n");
  188. System.out.println("that = "+that_);
  189. System.out.println("-----\n");
  190. KrbDelegationPermissionCollection nps =
  191. new KrbDelegationPermissionCollection();
  192. nps.add(this_);
  193. nps.add(new DelegationPermission("\"host/foo.example.com@EXAMPLE.COM\" \"CN=Gary Ellison/OU=JSN/O=SUNW/L=Palo Alto/ST=CA/C=US\""));
  194. try {
  195. nps.add(new DelegationPermission("host/foo.example.com@EXAMPLE.COM \"CN=Gary Ellison/OU=JSN/O=SUNW/L=Palo Alto/ST=CA/C=US\""));
  196. } catch (Exception e) {
  197. System.err.println(e);
  198. }
  199. System.out.println("nps.implies(that) = " + nps.implies(that_));
  200. System.out.println("-----\n");
  201. Enumeration e = nps.elements();
  202. while (e.hasMoreElements()) {
  203. DelegationPermission x =
  204. (DelegationPermission) e.nextElement();
  205. System.out.println("nps.e = " + x);
  206. }
  207. }
  208. */
  209. }
  210. final class KrbDelegationPermissionCollection extends PermissionCollection
  211. implements java.io.Serializable {
  212. // Not serialized; see serialization section at end of class.
  213. private transient List perms;
  214. public KrbDelegationPermissionCollection() {
  215. perms = new ArrayList();
  216. }
  217. /**
  218. * Check and see if this collection of permissions implies the permissions
  219. * expressed in "permission".
  220. *
  221. * @param p the Permission object to compare
  222. *
  223. * @return true if "permission" is a proper subset of a permission in
  224. * the collection, false if not.
  225. */
  226. public boolean implies(Permission permission) {
  227. if (! (permission instanceof DelegationPermission))
  228. return false;
  229. DelegationPermission np = (DelegationPermission) permission;
  230. synchronized (this) {
  231. int len = perms.size();
  232. for (int i = 0; i < len; i++) {
  233. DelegationPermission x = (DelegationPermission) perms.get(i);
  234. if (x.implies(np))
  235. return true;
  236. }
  237. }
  238. return false;
  239. }
  240. /**
  241. * Adds a permission to the DelegationPermissions. The key for
  242. * the hash is the name.
  243. *
  244. * @param permission the Permission object to add.
  245. *
  246. * @exception IllegalArgumentException - if the permission is not a
  247. * DelegationPermission
  248. *
  249. * @exception SecurityException - if this PermissionCollection object
  250. * has been marked readonly
  251. */
  252. public void add(Permission permission) {
  253. if (! (permission instanceof DelegationPermission))
  254. throw new IllegalArgumentException("invalid permission: "+
  255. permission);
  256. if (isReadOnly())
  257. throw new SecurityException("attempt to add a Permission to a readonly PermissionCollection");
  258. synchronized (this) {
  259. perms.add(0, permission);
  260. }
  261. }
  262. /**
  263. * Returns an enumeration of all the DelegationPermission objects
  264. * in the container.
  265. *
  266. * @return an enumeration of all the DelegationPermission objects.
  267. */
  268. public Enumeration elements() {
  269. // Convert Iterator into Enumeration
  270. synchronized (this) {
  271. return Collections.enumeration(perms);
  272. }
  273. }
  274. private static final long serialVersionUID = -3383936936589966948L;
  275. // Need to maintain serialization interoperability with earlier releases,
  276. // which had the serializable field:
  277. // private Vector permissions;
  278. /**
  279. * @serialField permissions java.util.Vector
  280. * A list of DelegationPermission objects.
  281. */
  282. private static final ObjectStreamField[] serialPersistentFields = {
  283. new ObjectStreamField("permissions", Vector.class),
  284. };
  285. /**
  286. * @serialData "permissions" field (a Vector containing the DelegationPermissions).
  287. */
  288. /*
  289. * Writes the contents of the perms field out as a Vector for
  290. * serialization compatibility with earlier releases.
  291. */
  292. private void writeObject(ObjectOutputStream out) throws IOException {
  293. // Don't call out.defaultWriteObject()
  294. // Write out Vector
  295. Vector permissions = new Vector(perms.size());
  296. synchronized (this) {
  297. permissions.addAll(perms);
  298. }
  299. ObjectOutputStream.PutField pfields = out.putFields();
  300. pfields.put("permissions", permissions);
  301. out.writeFields();
  302. }
  303. /*
  304. * Reads in a Vector of DelegationPermissions and saves them in the perms field.
  305. */
  306. private void readObject(ObjectInputStream in) throws IOException,
  307. ClassNotFoundException {
  308. // Don't call defaultReadObject()
  309. // Read in serialized fields
  310. ObjectInputStream.GetField gfields = in.readFields();
  311. // Get the one we want
  312. Vector permissions = (Vector)gfields.get("permissions", null);
  313. perms = new ArrayList(permissions.size());
  314. perms.addAll(permissions);
  315. }
  316. }