Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/javax/security/auth/PrivateCredentialPermission.java
38918 views
/*1* Copyright (c) 1999, 2013, 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;2627import java.util.*;28import java.text.MessageFormat;29import java.security.Permission;30import java.security.PermissionCollection;31import java.security.Principal;32import sun.security.util.ResourcesMgr;3334/**35* This class is used to protect access to private Credentials36* belonging to a particular {@code Subject}. The {@code Subject}37* is represented by a Set of Principals.38*39* <p> The target name of this {@code Permission} specifies40* a Credential class name, and a Set of Principals.41* The only valid value for this Permission's actions is, "read".42* The target name must abide by the following syntax:43*44* <pre>45* CredentialClass {PrincipalClass "PrincipalName"}*46* </pre>47*48* For example, the following permission grants access to the49* com.sun.PrivateCredential owned by Subjects which have50* a com.sun.Principal with the name, "duke". Note that although51* this example, as well as all the examples below, do not contain52* Codebase, SignedBy, or Principal information in the grant statement53* (for simplicity reasons), actual policy configurations should54* specify that information when appropriate.55*56* <pre>57*58* grant {59* permission javax.security.auth.PrivateCredentialPermission60* "com.sun.PrivateCredential com.sun.Principal \"duke\"",61* "read";62* };63* </pre>64*65* If CredentialClass is "*", then access is granted to66* all private Credentials belonging to the specified67* {@code Subject}.68* If "PrincipalName" is "*", then access is granted to the69* specified Credential owned by any {@code Subject} that has the70* specified {@code Principal} (the actual PrincipalName doesn't matter).71* For example, the following grants access to the72* a.b.Credential owned by any {@code Subject} that has73* an a.b.Principal.74*75* <pre>76* grant {77* permission javax.security.auth.PrivateCredentialPermission78* "a.b.Credential a.b.Principal "*"",79* "read";80* };81* </pre>82*83* If both the PrincipalClass and "PrincipalName" are "*",84* then access is granted to the specified Credential owned by85* any {@code Subject}.86*87* <p> In addition, the PrincipalClass/PrincipalName pairing may be repeated:88*89* <pre>90* grant {91* permission javax.security.auth.PrivateCredentialPermission92* "a.b.Credential a.b.Principal "duke" c.d.Principal "dukette"",93* "read";94* };95* </pre>96*97* The above grants access to the private Credential, "a.b.Credential",98* belonging to a {@code Subject} with at least two associated Principals:99* "a.b.Principal" with the name, "duke", and "c.d.Principal", with the name,100* "dukette".101*102*/103public final class PrivateCredentialPermission extends Permission {104105private static final long serialVersionUID = 5284372143517237068L;106107private static final CredOwner[] EMPTY_PRINCIPALS = new CredOwner[0];108109/**110* @serial111*/112private String credentialClass;113114/**115* @serial The Principals associated with this permission.116* The set contains elements of type,117* {@code PrivateCredentialPermission.CredOwner}.118*/119private Set<Principal> principals; // ignored - kept around for compatibility120private transient CredOwner[] credOwners;121122/**123* @serial124*/125private boolean testing = false;126127/**128* Create a new {@code PrivateCredentialPermission}129* with the specified {@code credentialClass} and Principals.130*/131PrivateCredentialPermission(String credentialClass,132Set<Principal> principals) {133134super(credentialClass);135this.credentialClass = credentialClass;136137synchronized(principals) {138if (principals.size() == 0) {139this.credOwners = EMPTY_PRINCIPALS;140} else {141this.credOwners = new CredOwner[principals.size()];142int index = 0;143Iterator<Principal> i = principals.iterator();144while (i.hasNext()) {145Principal p = i.next();146this.credOwners[index++] = new CredOwner147(p.getClass().getName(),148p.getName());149}150}151}152}153154/**155* Creates a new {@code PrivateCredentialPermission}156* with the specified {@code name}. The {@code name}157* specifies both a Credential class and a {@code Principal} Set.158*159* <p>160*161* @param name the name specifying the Credential class and162* {@code Principal} Set. <p>163*164* @param actions the actions specifying that the Credential can be read.165*166* @throws IllegalArgumentException if {@code name} does not conform167* to the correct syntax or if {@code actions} is not "read".168*/169public PrivateCredentialPermission(String name, String actions) {170super(name);171172if (!"read".equalsIgnoreCase(actions))173throw new IllegalArgumentException174(ResourcesMgr.getString("actions.can.only.be.read."));175init(name);176}177178/**179* Returns the Class name of the Credential associated with this180* {@code PrivateCredentialPermission}.181*182* <p>183*184* @return the Class name of the Credential associated with this185* {@code PrivateCredentialPermission}.186*/187public String getCredentialClass() {188return credentialClass;189}190191/**192* Returns the {@code Principal} classes and names193* associated with this {@code PrivateCredentialPermission}.194* The information is returned as a two-dimensional array (array[x][y]).195* The 'x' value corresponds to the number of {@code Principal}196* class and name pairs. When (y==0), it corresponds to197* the {@code Principal} class value, and when (y==1),198* it corresponds to the {@code Principal} name value.199* For example, array[0][0] corresponds to the class name of200* the first {@code Principal} in the array. array[0][1]201* corresponds to the {@code Principal} name of the202* first {@code Principal} in the array.203*204* <p>205*206* @return the {@code Principal} class and names associated207* with this {@code PrivateCredentialPermission}.208*/209public String[][] getPrincipals() {210211if (credOwners == null || credOwners.length == 0) {212return new String[0][0];213}214215String[][] pArray = new String[credOwners.length][2];216for (int i = 0; i < credOwners.length; i++) {217pArray[i][0] = credOwners[i].principalClass;218pArray[i][1] = credOwners[i].principalName;219}220return pArray;221}222223/**224* Checks if this {@code PrivateCredentialPermission} implies225* the specified {@code Permission}.226*227* <p>228*229* This method returns true if:230* <ul>231* <li> <i>p</i> is an instanceof PrivateCredentialPermission and232* <li> the target name for <i>p</i> is implied by this object's233* target name. For example:234* <pre>235* [* P1 "duke"] implies [a.b.Credential P1 "duke"].236* [C1 P1 "duke"] implies [C1 P1 "duke" P2 "dukette"].237* [C1 P2 "dukette"] implies [C1 P1 "duke" P2 "dukette"].238* </pre>239* </ul>240*241* <p>242*243* @param p the {@code Permission} to check against.244*245* @return true if this {@code PrivateCredentialPermission} implies246* the specified {@code Permission}, false if not.247*/248public boolean implies(Permission p) {249250if (p == null || !(p instanceof PrivateCredentialPermission))251return false;252253PrivateCredentialPermission that = (PrivateCredentialPermission)p;254255if (!impliesCredentialClass(credentialClass, that.credentialClass))256return false;257258return impliesPrincipalSet(credOwners, that.credOwners);259}260261/**262* Checks two {@code PrivateCredentialPermission} objects for263* equality. Checks that <i>obj</i> is a264* {@code PrivateCredentialPermission},265* and has the same credential class as this object,266* as well as the same Principals as this object.267* The order of the Principals in the respective Permission's268* target names is not relevant.269*270* <p>271*272* @param obj the object we are testing for equality with this object.273*274* @return true if obj is a {@code PrivateCredentialPermission},275* has the same credential class as this object,276* and has the same Principals as this object.277*/278public boolean equals(Object obj) {279if (obj == this)280return true;281282if (! (obj instanceof PrivateCredentialPermission))283return false;284285PrivateCredentialPermission that = (PrivateCredentialPermission)obj;286287return (this.implies(that) && that.implies(this));288}289290/**291* Returns the hash code value for this object.292*293* @return a hash code value for this object.294*/295public int hashCode() {296return this.credentialClass.hashCode();297}298299/**300* Returns the "canonical string representation" of the actions.301* This method always returns the String, "read".302*303* <p>304*305* @return the actions (always returns "read").306*/307public String getActions() {308return "read";309}310311/**312* Return a homogeneous collection of PrivateCredentialPermissions313* in a {@code PermissionCollection}.314* No such {@code PermissionCollection} is defined,315* so this method always returns {@code null}.316*317* <p>318*319* @return null in all cases.320*/321public PermissionCollection newPermissionCollection() {322return null;323}324325private void init(String name) {326327if (name == null || name.trim().length() == 0) {328throw new IllegalArgumentException("invalid empty name");329}330331ArrayList<CredOwner> pList = new ArrayList<>();332StringTokenizer tokenizer = new StringTokenizer(name, " ", true);333String principalClass = null;334String principalName = null;335336if (testing)337System.out.println("whole name = " + name);338339// get the Credential Class340credentialClass = tokenizer.nextToken();341if (testing)342System.out.println("Credential Class = " + credentialClass);343344if (tokenizer.hasMoreTokens() == false) {345MessageFormat form = new MessageFormat(ResourcesMgr.getString346("permission.name.name.syntax.invalid."));347Object[] source = {name};348throw new IllegalArgumentException349(form.format(source) + ResourcesMgr.getString350("Credential.Class.not.followed.by.a.Principal.Class.and.Name"));351}352353while (tokenizer.hasMoreTokens()) {354355// skip delimiter356tokenizer.nextToken();357358// get the Principal Class359principalClass = tokenizer.nextToken();360if (testing)361System.out.println(" Principal Class = " + principalClass);362363if (tokenizer.hasMoreTokens() == false) {364MessageFormat form = new MessageFormat(ResourcesMgr.getString365("permission.name.name.syntax.invalid."));366Object[] source = {name};367throw new IllegalArgumentException368(form.format(source) + ResourcesMgr.getString369("Principal.Class.not.followed.by.a.Principal.Name"));370}371372// skip delimiter373tokenizer.nextToken();374375// get the Principal Name376principalName = tokenizer.nextToken();377378if (!principalName.startsWith("\"")) {379MessageFormat form = new MessageFormat(ResourcesMgr.getString380("permission.name.name.syntax.invalid."));381Object[] source = {name};382throw new IllegalArgumentException383(form.format(source) + ResourcesMgr.getString384("Principal.Name.must.be.surrounded.by.quotes"));385}386387if (!principalName.endsWith("\"")) {388389// we have a name with spaces in it --390// keep parsing until we find the end quote,391// and keep the spaces in the name392393while (tokenizer.hasMoreTokens()) {394principalName = principalName + tokenizer.nextToken();395if (principalName.endsWith("\""))396break;397}398399if (!principalName.endsWith("\"")) {400MessageFormat form = new MessageFormat401(ResourcesMgr.getString402("permission.name.name.syntax.invalid."));403Object[] source = {name};404throw new IllegalArgumentException405(form.format(source) + ResourcesMgr.getString406("Principal.Name.missing.end.quote"));407}408}409410if (testing)411System.out.println("\tprincipalName = '" + principalName + "'");412413principalName = principalName.substring414(1, principalName.length() - 1);415416if (principalClass.equals("*") &&417!principalName.equals("*")) {418throw new IllegalArgumentException(ResourcesMgr.getString419("PrivateCredentialPermission.Principal.Class.can.not.be.a.wildcard.value.if.Principal.Name.is.not.a.wildcard.value"));420}421422if (testing)423System.out.println("\tprincipalName = '" + principalName + "'");424425pList.add(new CredOwner(principalClass, principalName));426}427428this.credOwners = new CredOwner[pList.size()];429pList.toArray(this.credOwners);430}431432private boolean impliesCredentialClass(String thisC, String thatC) {433434// this should never happen435if (thisC == null || thatC == null)436return false;437438if (testing)439System.out.println("credential class comparison: " +440thisC + "/" + thatC);441442if (thisC.equals("*"))443return true;444445/**446* XXX let's not enable this for now --447* if people want it, we'll enable it later448*/449/*450if (thisC.endsWith("*")) {451String cClass = thisC.substring(0, thisC.length() - 2);452return thatC.startsWith(cClass);453}454*/455456return thisC.equals(thatC);457}458459private boolean impliesPrincipalSet(CredOwner[] thisP, CredOwner[] thatP) {460461// this should never happen462if (thisP == null || thatP == null)463return false;464465if (thatP.length == 0)466return true;467468if (thisP.length == 0)469return false;470471for (int i = 0; i < thisP.length; i++) {472boolean foundMatch = false;473for (int j = 0; j < thatP.length; j++) {474if (thisP[i].implies(thatP[j])) {475foundMatch = true;476break;477}478}479if (!foundMatch) {480return false;481}482}483return true;484}485486/**487* Reads this object from a stream (i.e., deserializes it)488*/489private void readObject(java.io.ObjectInputStream s) throws490java.io.IOException,491ClassNotFoundException {492493s.defaultReadObject();494495// perform new initialization from the permission name496497if (getName().indexOf(" ") == -1 && getName().indexOf("\"") == -1) {498499// name only has a credential class specified500credentialClass = getName();501credOwners = EMPTY_PRINCIPALS;502503} else {504505// perform regular initialization506init(getName());507}508}509510/**511* @serial include512*/513static class CredOwner implements java.io.Serializable {514515private static final long serialVersionUID = -5607449830436408266L;516517/**518* @serial519*/520String principalClass;521/**522* @serial523*/524String principalName;525526CredOwner(String principalClass, String principalName) {527this.principalClass = principalClass;528this.principalName = principalName;529}530531public boolean implies(Object obj) {532if (obj == null || !(obj instanceof CredOwner))533return false;534535CredOwner that = (CredOwner)obj;536537if (principalClass.equals("*") ||538principalClass.equals(that.principalClass)) {539540if (principalName.equals("*") ||541principalName.equals(that.principalName)) {542return true;543}544}545546/**547* XXX no code yet to support a.b.*548*/549550return false;551}552553public String toString() {554MessageFormat form = new MessageFormat(ResourcesMgr.getString555("CredOwner.Principal.Class.class.Principal.Name.name"));556Object[] source = {principalClass, principalName};557return (form.format(source));558}559}560}561562563