blob: 5550f495de8399365b16298201cf0402fa4578b8 [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 2000-2006 Sun Microsystems, Inc. All Rights Reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26package javax.security.auth.kerberos;
27
28import java.util.*;
29import java.security.Permission;
30import java.security.BasicPermission;
31import java.security.PermissionCollection;
32import java.io.ObjectStreamField;
33import java.io.ObjectOutputStream;
34import java.io.ObjectInputStream;
35import java.io.IOException;
36
37/**
38 * This class is used to restrict the usage of the Kerberos
39 * delegation model, ie: forwardable and proxiable tickets.
40 * <p>
41 * The target name of this <code>Permission</code> specifies a pair of
42 * kerberos service principals. The first is the subordinate service principal
43 * being entrusted to use the TGT. The second service principal designates
44 * the target service the subordinate service principal is to
45 * interact with on behalf of the initiating KerberosPrincipal. This
46 * latter service principal is specified to restrict the use of a
47 * proxiable ticket.
48 * <p>
49 * For example, to specify the "host" service use of a forwardable TGT the
50 * target permission is specified as follows:
51 * <p>
52 * <pre>
53 * DelegationPermission("\"host/foo.example.com@EXAMPLE.COM\" \"krbtgt/EXAMPLE.COM@EXAMPLE.COM\"");
54 * </pre>
55 * <p>
56 * To give the "backup" service a proxiable nfs service ticket the target permission
57 * might be specified:
58 * <p>
59 * <pre>
60 * DelegationPermission("\"backup/bar.example.com@EXAMPLE.COM\" \"nfs/home.EXAMPLE.COM@EXAMPLE.COM\"");
61 * </pre>
62 *
63 * @since 1.4
64 */
65
66public final class DelegationPermission extends BasicPermission
67 implements java.io.Serializable {
68
69 private static final long serialVersionUID = 883133252142523922L;
70
71 private transient String subordinate, service;
72
73 /**
74 * Create a new <code>DelegationPermission</code>
75 * with the specified subordinate and target principals.
76 *
77 * <p>
78 *
79 * @param principals the name of the subordinate and target principals
80 *
81 * @throws NullPointerException if <code>principals</code> is <code>null</code>.
82 * @throws IllegalArgumentException if <code>principals</code> is empty.
83 */
84 public DelegationPermission(String principals) {
85 super(principals);
86 init(principals);
87 }
88
89 /**
90 * Create a new <code>DelegationPermission</code>
91 * with the specified subordinate and target principals.
92 * <p>
93 *
94 * @param principals the name of the subordinate and target principals
95 * <p>
96 * @param actions should be null.
97 *
98 * @throws NullPointerException if <code>principals</code> is <code>null</code>.
99 * @throws IllegalArgumentException if <code>principals</code> is empty.
100 */
101 public DelegationPermission(String principals, String actions) {
102 super(principals, actions);
103 init(principals);
104 }
105
106
107 /**
108 * Initialize the DelegationPermission object.
109 */
110 private void init(String target) {
111
112 StringTokenizer t = null;
113 if (!target.startsWith("\"")) {
114 throw new IllegalArgumentException
115 ("service principal [" + target +
116 "] syntax invalid: " +
117 "improperly quoted");
118 } else {
119 t = new StringTokenizer(target, "\"", false);
120 subordinate = t.nextToken();
121 if (t.countTokens() == 2) {
122 t.nextToken(); // bypass whitespace
123 service = t.nextToken();
124 } else if (t.countTokens() > 0) {
125 throw new IllegalArgumentException
126 ("service principal [" + t.nextToken() +
127 "] syntax invalid: " +
128 "improperly quoted");
129 }
130 }
131 }
132
133 /**
134 * Checks if this Kerberos delegation permission object "implies" the
135 * specified permission.
136 * <P>
137 * If none of the above are true, <code>implies</code> returns false.
138 * @param p the permission to check against.
139 *
140 * @return true if the specified permission is implied by this object,
141 * false if not.
142 */
143 public boolean implies(Permission p) {
144 if (!(p instanceof DelegationPermission))
145 return false;
146
147 DelegationPermission that = (DelegationPermission) p;
148 if (this.subordinate.equals(that.subordinate) &&
149 this.service.equals(that.service))
150 return true;
151
152 return false;
153 }
154
155
156 /**
157 * Checks two DelegationPermission objects for equality.
158 * <P>
159 * @param obj the object to test for equality with this object.
160 *
161 * @return true if <i>obj</i> is a DelegationPermission, and
162 * has the same subordinate and service principal as this.
163 * DelegationPermission object.
164 */
165 public boolean equals(Object obj) {
166 if (obj == this)
167 return true;
168
169 if (! (obj instanceof DelegationPermission))
170 return false;
171
172 DelegationPermission that = (DelegationPermission) obj;
173 return implies(that);
174 }
175
176 /**
177 * Returns the hash code value for this object.
178 *
179 * @return a hash code value for this object.
180 */
181
182 public int hashCode() {
183 return getName().hashCode();
184 }
185
186
187 /**
188 * Returns a PermissionCollection object for storing
189 * DelegationPermission objects.
190 * <br>
191 * DelegationPermission objects must be stored in a manner that
192 * allows them to be inserted into the collection in any order, but
193 * that also enables the PermissionCollection implies method to
194 * be implemented in an efficient (and consistent) manner.
195 *
196 * @return a new PermissionCollection object suitable for storing
197 * DelegationPermissions.
198 */
199
200 public PermissionCollection newPermissionCollection() {
201 return new KrbDelegationPermissionCollection();
202 }
203
204 /**
205 * WriteObject is called to save the state of the DelegationPermission
206 * to a stream. The actions are serialized, and the superclass
207 * takes care of the name.
208 */
209 private synchronized void writeObject(java.io.ObjectOutputStream s)
210 throws IOException
211 {
212 s.defaultWriteObject();
213 }
214
215 /**
216 * readObject is called to restore the state of the
217 * DelegationPermission from a stream.
218 */
219 private synchronized void readObject(java.io.ObjectInputStream s)
220 throws IOException, ClassNotFoundException
221 {
222 // Read in the action, then initialize the rest
223 s.defaultReadObject();
224 init(getName());
225 }
226
227 /*
228 public static void main(String args[]) throws Exception {
229 DelegationPermission this_ =
230 new DelegationPermission(args[0]);
231 DelegationPermission that_ =
232 new DelegationPermission(args[1]);
233 System.out.println("-----\n");
234 System.out.println("this.implies(that) = " + this_.implies(that_));
235 System.out.println("-----\n");
236 System.out.println("this = "+this_);
237 System.out.println("-----\n");
238 System.out.println("that = "+that_);
239 System.out.println("-----\n");
240
241 KrbDelegationPermissionCollection nps =
242 new KrbDelegationPermissionCollection();
243 nps.add(this_);
244 nps.add(new DelegationPermission("\"host/foo.example.com@EXAMPLE.COM\" \"CN=Gary Ellison/OU=JSN/O=SUNW/L=Palo Alto/ST=CA/C=US\""));
245 try {
246 nps.add(new DelegationPermission("host/foo.example.com@EXAMPLE.COM \"CN=Gary Ellison/OU=JSN/O=SUNW/L=Palo Alto/ST=CA/C=US\""));
247 } catch (Exception e) {
248 System.err.println(e);
249 }
250
251 System.out.println("nps.implies(that) = " + nps.implies(that_));
252 System.out.println("-----\n");
253
254 Enumeration e = nps.elements();
255
256 while (e.hasMoreElements()) {
257 DelegationPermission x =
258 (DelegationPermission) e.nextElement();
259 System.out.println("nps.e = " + x);
260 }
261 }
262 */
263}
264
265
266final class KrbDelegationPermissionCollection extends PermissionCollection
267 implements java.io.Serializable {
268
269 // Not serialized; see serialization section at end of class.
270 private transient List<Permission> perms;
271
272 public KrbDelegationPermissionCollection() {
273 perms = new ArrayList<Permission>();
274 }
275
276
277 /**
278 * Check and see if this collection of permissions implies the permissions
279 * expressed in "permission".
280 *
281 * @param p the Permission object to compare
282 *
283 * @return true if "permission" is a proper subset of a permission in
284 * the collection, false if not.
285 */
286
287 public boolean implies(Permission permission) {
288 if (! (permission instanceof DelegationPermission))
289 return false;
290
291 synchronized (this) {
292 for (Permission x : perms) {
293 if (x.implies(permission))
294 return true;
295 }
296 }
297 return false;
298
299 }
300
301 /**
302 * Adds a permission to the DelegationPermissions. The key for
303 * the hash is the name.
304 *
305 * @param permission the Permission object to add.
306 *
307 * @exception IllegalArgumentException - if the permission is not a
308 * DelegationPermission
309 *
310 * @exception SecurityException - if this PermissionCollection object
311 * has been marked readonly
312 */
313
314 public void add(Permission permission) {
315 if (! (permission instanceof DelegationPermission))
316 throw new IllegalArgumentException("invalid permission: "+
317 permission);
318 if (isReadOnly())
319 throw new SecurityException("attempt to add a Permission to a readonly PermissionCollection");
320
321 synchronized (this) {
322 perms.add(0, permission);
323 }
324 }
325
326 /**
327 * Returns an enumeration of all the DelegationPermission objects
328 * in the container.
329 *
330 * @return an enumeration of all the DelegationPermission objects.
331 */
332
333 public Enumeration<Permission> elements() {
334 // Convert Iterator into Enumeration
335 synchronized (this) {
336 return Collections.enumeration(perms);
337 }
338 }
339
340 private static final long serialVersionUID = -3383936936589966948L;
341
342 // Need to maintain serialization interoperability with earlier releases,
343 // which had the serializable field:
344 // private Vector permissions;
345 /**
346 * @serialField permissions java.util.Vector
347 * A list of DelegationPermission objects.
348 */
349 private static final ObjectStreamField[] serialPersistentFields = {
350 new ObjectStreamField("permissions", Vector.class),
351 };
352
353 /**
354 * @serialData "permissions" field (a Vector containing the DelegationPermissions).
355 */
356 /*
357 * Writes the contents of the perms field out as a Vector for
358 * serialization compatibility with earlier releases.
359 */
360 private void writeObject(ObjectOutputStream out) throws IOException {
361 // Don't call out.defaultWriteObject()
362
363 // Write out Vector
364 Vector<Permission> permissions = new Vector<Permission>(perms.size());
365
366 synchronized (this) {
367 permissions.addAll(perms);
368 }
369
370 ObjectOutputStream.PutField pfields = out.putFields();
371 pfields.put("permissions", permissions);
372 out.writeFields();
373 }
374
375 /*
376 * Reads in a Vector of DelegationPermissions and saves them in the perms field.
377 */
378 private void readObject(ObjectInputStream in) throws IOException,
379 ClassNotFoundException {
380 // Don't call defaultReadObject()
381
382 // Read in serialized fields
383 ObjectInputStream.GetField gfields = in.readFields();
384
385 // Get the one we want
386 Vector<Permission> permissions =
387 (Vector<Permission>)gfields.get("permissions", null);
388 perms = new ArrayList<Permission>(permissions.size());
389 perms.addAll(permissions);
390 }
391}