001 /*
002 * Copyright 2000-2006 Sun Microsystems, Inc. All Rights Reserved.
003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004 *
005 * This code is free software; you can redistribute it and/or modify it
006 * under the terms of the GNU General Public License version 2 only, as
007 * published by the Free Software Foundation. Sun designates this
008 * particular file as subject to the "Classpath" exception as provided
009 * by Sun in the LICENSE file that accompanied this code.
010 *
011 * This code is distributed in the hope that it will be useful, but WITHOUT
012 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014 * version 2 for more details (a copy is included in the LICENSE file that
015 * accompanied this code).
016 *
017 * You should have received a copy of the GNU General Public License version
018 * 2 along with this work; if not, write to the Free Software Foundation,
019 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020 *
021 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022 * CA 95054 USA or visit www.sun.com if you need additional information or
023 * have any questions.
024 */
025
026 package javax.security.auth.kerberos;
027
028 import java.util.*;
029 import java.security.Permission;
030 import java.security.BasicPermission;
031 import java.security.PermissionCollection;
032 import java.io.ObjectStreamField;
033 import java.io.ObjectOutputStream;
034 import java.io.ObjectInputStream;
035 import java.io.IOException;
036
037 /**
038 * This class is used to restrict the usage of the Kerberos
039 * delegation model, ie: forwardable and proxiable tickets.
040 * <p>
041 * The target name of this <code>Permission</code> specifies a pair of
042 * kerberos service principals. The first is the subordinate service principal
043 * being entrusted to use the TGT. The second service principal designates
044 * the target service the subordinate service principal is to
045 * interact with on behalf of the initiating KerberosPrincipal. This
046 * latter service principal is specified to restrict the use of a
047 * proxiable ticket.
048 * <p>
049 * For example, to specify the "host" service use of a forwardable TGT the
050 * target permission is specified as follows:
051 * <p>
052 * <pre>
053 * DelegationPermission("\"host/foo.example.com@EXAMPLE.COM\" \"krbtgt/EXAMPLE.COM@EXAMPLE.COM\"");
054 * </pre>
055 * <p>
056 * To give the "backup" service a proxiable nfs service ticket the target permission
057 * might be specified:
058 * <p>
059 * <pre>
060 * DelegationPermission("\"backup/bar.example.com@EXAMPLE.COM\" \"nfs/home.EXAMPLE.COM@EXAMPLE.COM\"");
061 * </pre>
062 *
063 * @since 1.4
064 */
065
066 public final class DelegationPermission extends BasicPermission
067 implements java.io.Serializable {
068
069 private static final long serialVersionUID = 883133252142523922L;
070
071 private transient String subordinate, service;
072
073 /**
074 * Create a new <code>DelegationPermission</code>
075 * with the specified subordinate and target principals.
076 *
077 * <p>
078 *
079 * @param principals the name of the subordinate and target principals
080 *
081 * @throws NullPointerException if <code>principals</code> is <code>null</code>.
082 * @throws IllegalArgumentException if <code>principals</code> is empty.
083 */
084 public DelegationPermission(String principals) {
085 super (principals);
086 init(principals);
087 }
088
089 /**
090 * Create a new <code>DelegationPermission</code>
091 * with the specified subordinate and target principals.
092 * <p>
093 *
094 * @param principals the name of the subordinate and target principals
095 * <p>
096 * @param actions should be null.
097 *
098 * @throws NullPointerException if <code>principals</code> is <code>null</code>.
099 * @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 * Initialize the DelegationPermission object.
108 */
109 private void init(String target) {
110
111 StringTokenizer t = null;
112 if (!target.startsWith("\"")) {
113 throw new IllegalArgumentException("service principal ["
114 + target + "] syntax invalid: "
115 + "improperly quoted");
116 } else {
117 t = new StringTokenizer(target, "\"", false);
118 subordinate = t.nextToken();
119 if (t.countTokens() == 2) {
120 t.nextToken(); // bypass whitespace
121 service = t.nextToken();
122 } else if (t.countTokens() > 0) {
123 throw new IllegalArgumentException(
124 "service principal [" + t.nextToken()
125 + "] syntax invalid: "
126 + "improperly quoted");
127 }
128 }
129 }
130
131 /**
132 * Checks if this Kerberos delegation permission object "implies" the
133 * specified permission.
134 * <P>
135 * If none of the above are true, <code>implies</code> returns false.
136 * @param p the permission to check against.
137 *
138 * @return true if the specified permission is implied by this object,
139 * false if not.
140 */
141 public boolean implies(Permission p) {
142 if (!(p instanceof DelegationPermission))
143 return false;
144
145 DelegationPermission that = (DelegationPermission) p;
146 if (this .subordinate.equals(that.subordinate)
147 && this .service.equals(that.service))
148 return true;
149
150 return false;
151 }
152
153 /**
154 * Checks two DelegationPermission objects for equality.
155 * <P>
156 * @param obj the object to test for equality with this object.
157 *
158 * @return true if <i>obj</i> is a DelegationPermission, and
159 * has the same subordinate and service principal as this.
160 * DelegationPermission object.
161 */
162 public boolean equals(Object obj) {
163 if (obj == this )
164 return true;
165
166 if (!(obj instanceof DelegationPermission))
167 return false;
168
169 DelegationPermission that = (DelegationPermission) obj;
170 return implies(that);
171 }
172
173 /**
174 * Returns the hash code value for this object.
175 *
176 * @return a hash code value for this object.
177 */
178
179 public int hashCode() {
180 return getName().hashCode();
181 }
182
183 /**
184 * Returns a PermissionCollection object for storing
185 * DelegationPermission objects.
186 * <br>
187 * DelegationPermission objects must be stored in a manner that
188 * allows them to be inserted into the collection in any order, but
189 * that also enables the PermissionCollection implies method to
190 * be implemented in an efficient (and consistent) manner.
191 *
192 * @return a new PermissionCollection object suitable for storing
193 * DelegationPermissions.
194 */
195
196 public PermissionCollection newPermissionCollection() {
197 return new KrbDelegationPermissionCollection();
198 }
199
200 /**
201 * WriteObject is called to save the state of the DelegationPermission
202 * to a stream. The actions are serialized, and the superclass
203 * takes care of the name.
204 */
205 private synchronized void writeObject(java.io.ObjectOutputStream s)
206 throws IOException {
207 s.defaultWriteObject();
208 }
209
210 /**
211 * readObject is called to restore the state of the
212 * DelegationPermission from a stream.
213 */
214 private synchronized void readObject(java.io.ObjectInputStream s)
215 throws IOException, ClassNotFoundException {
216 // Read in the action, then initialize the rest
217 s.defaultReadObject();
218 init(getName());
219 }
220
221 /*
222 public static void main(String args[]) throws Exception {
223 DelegationPermission this_ =
224 new DelegationPermission(args[0]);
225 DelegationPermission that_ =
226 new DelegationPermission(args[1]);
227 System.out.println("-----\n");
228 System.out.println("this.implies(that) = " + this_.implies(that_));
229 System.out.println("-----\n");
230 System.out.println("this = "+this_);
231 System.out.println("-----\n");
232 System.out.println("that = "+that_);
233 System.out.println("-----\n");
234
235 KrbDelegationPermissionCollection nps =
236 new KrbDelegationPermissionCollection();
237 nps.add(this_);
238 nps.add(new DelegationPermission("\"host/foo.example.com@EXAMPLE.COM\" \"CN=Gary Ellison/OU=JSN/O=SUNW/L=Palo Alto/ST=CA/C=US\""));
239 try {
240 nps.add(new DelegationPermission("host/foo.example.com@EXAMPLE.COM \"CN=Gary Ellison/OU=JSN/O=SUNW/L=Palo Alto/ST=CA/C=US\""));
241 } catch (Exception e) {
242 System.err.println(e);
243 }
244
245 System.out.println("nps.implies(that) = " + nps.implies(that_));
246 System.out.println("-----\n");
247
248 Enumeration e = nps.elements();
249
250 while (e.hasMoreElements()) {
251 DelegationPermission x =
252 (DelegationPermission) e.nextElement();
253 System.out.println("nps.e = " + x);
254 }
255 }
256 */
257 }
258
259 final class KrbDelegationPermissionCollection extends
260 PermissionCollection implements java.io.Serializable {
261
262 // Not serialized; see serialization section at end of class.
263 private transient List<Permission> perms;
264
265 public KrbDelegationPermissionCollection() {
266 perms = new ArrayList<Permission>();
267 }
268
269 /**
270 * Check and see if this collection of permissions implies the permissions
271 * expressed in "permission".
272 *
273 * @param p the Permission object to compare
274 *
275 * @return true if "permission" is a proper subset of a permission in
276 * the collection, false if not.
277 */
278
279 public boolean implies(Permission permission) {
280 if (!(permission instanceof DelegationPermission))
281 return false;
282
283 synchronized (this ) {
284 for (Permission x : perms) {
285 if (x.implies(permission))
286 return true;
287 }
288 }
289 return false;
290
291 }
292
293 /**
294 * Adds a permission to the DelegationPermissions. The key for
295 * the hash is the name.
296 *
297 * @param permission the Permission object to add.
298 *
299 * @exception IllegalArgumentException - if the permission is not a
300 * DelegationPermission
301 *
302 * @exception SecurityException - if this PermissionCollection object
303 * has been marked readonly
304 */
305
306 public void add(Permission permission) {
307 if (!(permission instanceof DelegationPermission))
308 throw new IllegalArgumentException("invalid permission: "
309 + permission);
310 if (isReadOnly())
311 throw new SecurityException(
312 "attempt to add a Permission to a readonly PermissionCollection");
313
314 synchronized (this ) {
315 perms.add(0, permission);
316 }
317 }
318
319 /**
320 * Returns an enumeration of all the DelegationPermission objects
321 * in the container.
322 *
323 * @return an enumeration of all the DelegationPermission objects.
324 */
325
326 public Enumeration<Permission> elements() {
327 // Convert Iterator into Enumeration
328 synchronized (this ) {
329 return Collections.enumeration(perms);
330 }
331 }
332
333 private static final long serialVersionUID = -3383936936589966948L;
334
335 // Need to maintain serialization interoperability with earlier releases,
336 // which had the serializable field:
337 // private Vector permissions;
338 /**
339 * @serialField permissions java.util.Vector
340 * A list of DelegationPermission objects.
341 */
342 private static final ObjectStreamField[] serialPersistentFields = { new ObjectStreamField(
343 "permissions", Vector.class), };
344
345 /**
346 * @serialData "permissions" field (a Vector containing the DelegationPermissions).
347 */
348 /*
349 * Writes the contents of the perms field out as a Vector for
350 * serialization compatibility with earlier releases.
351 */
352 private void writeObject(ObjectOutputStream out) throws IOException {
353 // Don't call out.defaultWriteObject()
354
355 // Write out Vector
356 Vector<Permission> permissions = new Vector<Permission>(perms
357 .size());
358
359 synchronized (this ) {
360 permissions.addAll(perms);
361 }
362
363 ObjectOutputStream.PutField pfields = out.putFields();
364 pfields.put("permissions", permissions);
365 out.writeFields();
366 }
367
368 /*
369 * Reads in a Vector of DelegationPermissions and saves them in the perms field.
370 */
371 private void readObject(ObjectInputStream in) throws IOException,
372 ClassNotFoundException {
373 // Don't call defaultReadObject()
374
375 // Read in serialized fields
376 ObjectInputStream.GetField gfields = in.readFields();
377
378 // Get the one we want
379 Vector<Permission> permissions = (Vector<Permission>) gfields
380 .get("permissions", null);
381 perms = new ArrayList<Permission>(permissions.size());
382 perms.addAll(permissions);
383 }
384 }
|