Path: blob/master/src/java.security.jgss/share/classes/javax/security/auth/kerberos/DelegationPermission.java
41161 views
/*1* Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package javax.security.auth.kerberos;2627import java.io.IOException;28import java.io.ObjectInputStream;29import java.io.ObjectOutputStream;30import java.io.ObjectStreamField;31import java.security.BasicPermission;32import java.security.Permission;33import java.security.PermissionCollection;34import java.util.*;35import java.util.concurrent.ConcurrentHashMap;3637/**38* This class is used to restrict the usage of the Kerberos39* delegation model, ie: forwardable and proxiable tickets.40* <p>41* The target name of this {@code Permission} specifies a pair of42* kerberos service principals. The first is the subordinate service principal43* being entrusted to use the TGT. The second service principal designates44* the target service the subordinate service principal is to45* interact with on behalf of the initiating KerberosPrincipal. This46* latter service principal is specified to restrict the use of a47* proxiable ticket.48* <p>49* For example, to specify the "host" service use of a forwardable TGT the50* target permission is specified as follows:51*52* <pre>53* DelegationPermission("\"host/[email protected]\" \"krbtgt/[email protected]\"");54* </pre>55* <p>56* To give the "backup" service a proxiable nfs service ticket the target permission57* might be specified:58*59* <pre>60* DelegationPermission("\"backup/[email protected]\" \"nfs/[email protected]\"");61* </pre>62*63* @since 1.464*/6566public final class DelegationPermission extends BasicPermission67implements java.io.Serializable {6869private static final long serialVersionUID = 883133252142523922L;7071private transient String subordinate, service;7273/**74* Create a new {@code DelegationPermission}75* with the specified subordinate and target principals.76*77* @param principals the name of the subordinate and target principals78*79* @throws NullPointerException if {@code principals} is {@code null}.80* @throws IllegalArgumentException if {@code principals} is empty,81* or does not contain a pair of principals, or is improperly quoted82*/83public DelegationPermission(String principals) {84super(principals);85init(principals);86}8788/**89* Create a new {@code DelegationPermission}90* with the specified subordinate and target principals.91*92* @param principals the name of the subordinate and target principals93*94* @param actions should be null.95*96* @throws NullPointerException if {@code principals} is {@code null}.97* @throws IllegalArgumentException if {@code principals} is empty,98* or does not contain a pair of principals, or is improperly quoted99*/100public DelegationPermission(String principals, String actions) {101super(principals, actions);102init(principals);103}104105106/**107* Initialize the DelegationPermission object.108*/109private void init(String target) {110111// 7 tokens in a string:112// "subordinate@R1" "service@R2"113// 1<------2----->345<----6--->7114StringTokenizer t = new StringTokenizer(target, "\"", true);115try {116if (!t.nextToken().equals("\"")) { // 1117throw new IllegalArgumentException("Illegal input [" + target118+ "]: improperly quoted");119}120subordinate = t.nextToken(); // 2121if (subordinate.equals("\"")) {122throw new IllegalArgumentException("Illegal input [" + target123+ "]: bad subordinate name");124}125t.nextToken(); // 3126if (!t.nextToken().trim().isEmpty()) { // 4127throw new IllegalArgumentException("Illegal input [" + target128+ "]: improperly separated");129}130t.nextToken(); // 5131service = t.nextToken(); // 6132if (service.equals("\"")) {133throw new IllegalArgumentException("Illegal input [" + target134+ "]: bad service name");135}136t.nextToken(); // 7137} catch (NoSuchElementException e) {138throw new IllegalArgumentException("Illegal input [" + target139+ "]: not enough input");140}141if (t.hasMoreTokens()) {142throw new IllegalArgumentException("Illegal input [" + target143+ "]: extra input");144}145}146147/**148* Checks if this Kerberos delegation permission object "implies" the149* specified permission.150* <P>151* This method returns true if this {@code DelegationPermission}152* is equal to {@code p}, and returns false otherwise.153*154* @param p the permission to check against.155*156* @return true if the specified permission is implied by this object,157* false if not.158*/159@Override160public boolean implies(Permission p) {161return equals(p);162}163164/**165* Checks two DelegationPermission objects for equality.166*167* @param obj the object to test for equality with this object.168*169* @return true if {@code obj} is a DelegationPermission, and170* has the same subordinate and service principal as this171* DelegationPermission object.172*/173@Override174public boolean equals(Object obj) {175if (obj == this) {176return true;177}178179if (!(obj instanceof DelegationPermission)) {180return false;181}182183DelegationPermission that = (DelegationPermission) obj;184185return this.subordinate.equals(that.subordinate) &&186this.service.equals(that.service);187}188189/**190* Returns the hash code value for this object.191*192* @return a hash code value for this object.193*/194@Override195public int hashCode() {196return 17 * subordinate.hashCode() + 31 * service.hashCode();197}198199/**200* Returns a PermissionCollection object for storing201* DelegationPermission objects.202* <br>203* DelegationPermission objects must be stored in a manner that204* allows them to be inserted into the collection in any order, but205* that also enables the PermissionCollection implies method to206* be implemented in an efficient (and consistent) manner.207*208* @return a new PermissionCollection object suitable for storing209* DelegationPermissions.210*/211@Override212public PermissionCollection newPermissionCollection() {213return new KrbDelegationPermissionCollection();214}215216/**217* WriteObject is called to save the state of the DelegationPermission218* to a stream. The actions are serialized, and the superclass219* takes care of the name.220*221* @param s the {@code ObjectOutputStream} to which data is written222* @throws IOException if an I/O error occurs223*/224private synchronized void writeObject(java.io.ObjectOutputStream s)225throws IOException226{227s.defaultWriteObject();228}229230/**231* readObject is called to restore the state of the232* DelegationPermission from a stream.233*234* @param s the {@code ObjectInputStream} from which data is read235* @throws IOException if an I/O error occurs236* @throws ClassNotFoundException if a serialized class cannot be loaded237*/238private synchronized void readObject(java.io.ObjectInputStream s)239throws IOException, ClassNotFoundException240{241// Read in the action, then initialize the rest242s.defaultReadObject();243init(getName());244}245246}247248249final class KrbDelegationPermissionCollection extends PermissionCollection250implements java.io.Serializable {251252// Not serialized; see serialization section at end of class.253private transient ConcurrentHashMap<Permission, Boolean> perms;254255public KrbDelegationPermissionCollection() {256perms = new ConcurrentHashMap<>();257}258259/**260* Check and see if this collection of permissions implies the permissions261* expressed in "permission".262*263* @param permission the Permission object to compare264*265* @return true if "permission" is a proper subset of a permission in266* the collection, false if not.267*/268@Override269public boolean implies(Permission permission) {270if (! (permission instanceof DelegationPermission))271return false;272273// if map contains key, then it automatically implies it274return perms.containsKey(permission);275}276277/**278* Adds a permission to the DelegationPermissions. The key for279* the hash is the name.280*281* @param permission the Permission object to add.282*283* @exception IllegalArgumentException - if the permission is not a284* DelegationPermission285*286* @exception SecurityException - if this PermissionCollection object287* has been marked readonly288*/289@Override290public void add(Permission permission) {291if (! (permission instanceof DelegationPermission))292throw new IllegalArgumentException("invalid permission: "+293permission);294if (isReadOnly())295throw new SecurityException("attempt to add a Permission to a readonly PermissionCollection");296297perms.put(permission, Boolean.TRUE);298}299300/**301* Returns an enumeration of all the DelegationPermission objects302* in the container.303*304* @return an enumeration of all the DelegationPermission objects.305*/306@Override307public Enumeration<Permission> elements() {308return perms.keys();309}310311private static final long serialVersionUID = -3383936936589966948L;312313// Need to maintain serialization interoperability with earlier releases,314// which had the serializable field:315// private Vector permissions;316/**317* @serialField permissions java.util.Vector318* A list of DelegationPermission objects.319*/320private static final ObjectStreamField[] serialPersistentFields = {321new ObjectStreamField("permissions", Vector.class),322};323324/**325* @serialData "permissions" field (a Vector containing the DelegationPermissions).326*/327/*328* Writes the contents of the perms field out as a Vector for329* serialization compatibility with earlier releases.330*/331private void writeObject(ObjectOutputStream out) throws IOException {332// Don't call out.defaultWriteObject()333334// Write out Vector335Vector<Permission> permissions = new Vector<>(perms.keySet());336337ObjectOutputStream.PutField pfields = out.putFields();338pfields.put("permissions", permissions);339out.writeFields();340}341342/*343* Reads in a Vector of DelegationPermissions and saves them in the perms field.344*/345@SuppressWarnings("unchecked")346private void readObject(ObjectInputStream in)347throws IOException, ClassNotFoundException348{349// Don't call defaultReadObject()350351// Read in serialized fields352ObjectInputStream.GetField gfields = in.readFields();353354// Get the one we want355Vector<Permission> permissions =356(Vector<Permission>)gfields.get("permissions", null);357perms = new ConcurrentHashMap<>(permissions.size());358for (Permission perm : permissions) {359perms.put(perm, Boolean.TRUE);360}361}362}363364365