1 /* 2 * Copyright (c) 2000, 2013, Oracle and/or its affiliates. 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. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package javax.security.auth.kerberos; 27 28 import java.util.*; 29 import java.security.Permission; 30 import java.security.BasicPermission; 31 import java.security.PermissionCollection; 32 import java.io.ObjectStreamField; 33 import java.io.ObjectOutputStream; 34 import java.io.ObjectInputStream; 35 import 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} 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 * 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 * 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 66 public 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} 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} is {@code null}. 82 * @throws IllegalArgumentException if {@code principals} is empty. 83 */ 84 public DelegationPermission(String principals) { 85 super(principals); 86 init(principals); 87 } 88 89 /** 90 * Create a new {@code DelegationPermission} 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} is {@code null}. 99 * @throws IllegalArgumentException if {@code principals} 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} 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 public int hashCode() { 182 return getName().hashCode(); 183 } 184 185 186 /** 187 * Returns a PermissionCollection object for storing 188 * DelegationPermission objects. 189 * <br> 190 * DelegationPermission objects must be stored in a manner that 191 * allows them to be inserted into the collection in any order, but 192 * that also enables the PermissionCollection implies method to 193 * be implemented in an efficient (and consistent) manner. 194 * 195 * @return a new PermissionCollection object suitable for storing 196 * DelegationPermissions. 197 */ 198 199 public PermissionCollection newPermissionCollection() { 200 return new KrbDelegationPermissionCollection(); 201 } 202 203 /** 204 * WriteObject is called to save the state of the DelegationPermission 205 * to a stream. The actions are serialized, and the superclass 206 * takes care of the name. 207 */ 208 private synchronized void writeObject(java.io.ObjectOutputStream s) 209 throws IOException 210 { 211 s.defaultWriteObject(); 212 } 213 214 /** 215 * readObject is called to restore the state of the 216 * DelegationPermission from a stream. 217 */ 218 private synchronized void readObject(java.io.ObjectInputStream s) 219 throws IOException, ClassNotFoundException 220 { 221 // Read in the action, then initialize the rest 222 s.defaultReadObject(); 223 init(getName()); 224 } 225 226 /* 227 public static void main(String args[]) throws Exception { 228 DelegationPermission this_ = 229 new DelegationPermission(args[0]); 230 DelegationPermission that_ = 231 new DelegationPermission(args[1]); 232 System.out.println("-----\n"); 233 System.out.println("this.implies(that) = " + this_.implies(that_)); 234 System.out.println("-----\n"); 235 System.out.println("this = "+this_); 236 System.out.println("-----\n"); 237 System.out.println("that = "+that_); 238 System.out.println("-----\n"); 239 240 KrbDelegationPermissionCollection nps = 241 new KrbDelegationPermissionCollection(); 242 nps.add(this_); 243 nps.add(new DelegationPermission("\"host/foo.example.com@EXAMPLE.COM\" \"CN=Gary Ellison/OU=JSN/O=SUNW/L=Palo Alto/ST=CA/C=US\"")); 244 try { 245 nps.add(new DelegationPermission("host/foo.example.com@EXAMPLE.COM \"CN=Gary Ellison/OU=JSN/O=SUNW/L=Palo Alto/ST=CA/C=US\"")); 246 } catch (Exception e) { 247 System.err.println(e); 248 } 249 250 System.out.println("nps.implies(that) = " + nps.implies(that_)); 251 System.out.println("-----\n"); 252 253 Enumeration e = nps.elements(); 254 255 while (e.hasMoreElements()) { 256 DelegationPermission x = 257 (DelegationPermission) e.nextElement(); 258 System.out.println("nps.e = " + x); 259 } 260 } 261 */ 262 } 263 264 265 final class KrbDelegationPermissionCollection extends PermissionCollection 266 implements java.io.Serializable { 267 268 // Not serialized; see serialization section at end of class. 269 private transient List<Permission> perms; 270 271 public KrbDelegationPermissionCollection() { 272 perms = new ArrayList<Permission>(); 273 } 274 275 276 /** 277 * Check and see if this collection of permissions implies the permissions 278 * expressed in "permission". 279 * 280 * @param permission the Permission object to compare 281 * 282 * @return true if "permission" is a proper subset of a permission in 283 * the collection, false if not. 284 */ 285 public boolean implies(Permission permission) { 286 if (! (permission instanceof DelegationPermission)) 287 return false; 288 289 synchronized (this) { 290 for (Permission x : perms) { 291 if (x.implies(permission)) 292 return true; 293 } 294 } 295 return false; 296 297 } 298 299 /** 300 * Adds a permission to the DelegationPermissions. The key for 301 * the hash is the name. 302 * 303 * @param permission the Permission object to add. 304 * 305 * @exception IllegalArgumentException - if the permission is not a 306 * DelegationPermission 307 * 308 * @exception SecurityException - if this PermissionCollection object 309 * has been marked readonly 310 */ 311 public void add(Permission permission) { 312 if (! (permission instanceof DelegationPermission)) 313 throw new IllegalArgumentException("invalid permission: "+ 314 permission); 315 if (isReadOnly()) 316 throw new SecurityException("attempt to add a Permission to a readonly PermissionCollection"); 317 318 synchronized (this) { 319 perms.add(0, permission); 320 } 321 } 322 323 /** 324 * Returns an enumeration of all the DelegationPermission objects 325 * in the container. 326 * 327 * @return an enumeration of all the DelegationPermission objects. 328 */ 329 public Enumeration<Permission> elements() { 330 // Convert Iterator into Enumeration 331 synchronized (this) { 332 return Collections.enumeration(perms); 333 } 334 } 335 336 private static final long serialVersionUID = -3383936936589966948L; 337 338 // Need to maintain serialization interoperability with earlier releases, 339 // which had the serializable field: 340 // private Vector permissions; 341 /** 342 * @serialField permissions java.util.Vector 343 * A list of DelegationPermission objects. 344 */ 345 private static final ObjectStreamField[] serialPersistentFields = { 346 new ObjectStreamField("permissions", Vector.class), 347 }; 348 349 /** 350 * @serialData "permissions" field (a Vector containing the DelegationPermissions). 351 */ 352 /* 353 * Writes the contents of the perms field out as a Vector for 354 * serialization compatibility with earlier releases. 355 */ 356 private void writeObject(ObjectOutputStream out) throws IOException { 357 // Don't call out.defaultWriteObject() 358 359 // Write out Vector 360 Vector<Permission> permissions = new Vector<>(perms.size()); 361 362 synchronized (this) { 363 permissions.addAll(perms); 364 } 365 366 ObjectOutputStream.PutField pfields = out.putFields(); 367 pfields.put("permissions", permissions); 368 out.writeFields(); 369 } 370 371 /* 372 * Reads in a Vector of DelegationPermissions and saves them in the perms field. 373 */ 374 @SuppressWarnings("unchecked") 375 private void readObject(ObjectInputStream in) 376 throws IOException, ClassNotFoundException 377 { 378 // Don't call defaultReadObject() 379 380 // Read in serialized fields 381 ObjectInputStream.GetField gfields = in.readFields(); 382 383 // Get the one we want 384 Vector<Permission> permissions = 385 (Vector<Permission>)gfields.get("permissions", null); 386 perms = new ArrayList<Permission>(permissions.size()); 387 perms.addAll(permissions); 388 } 389 }