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