0N/A/*
3909N/A * Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved.
0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0N/A *
0N/A * This code is free software; you can redistribute it and/or modify it
0N/A * under the terms of the GNU General Public License version 2 only, as
2362N/A * published by the Free Software Foundation. Oracle designates this
0N/A * particular file as subject to the "Classpath" exception as provided
2362N/A * by Oracle in the LICENSE file that accompanied this code.
0N/A *
0N/A * This code is distributed in the hope that it will be useful, but WITHOUT
0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0N/A * version 2 for more details (a copy is included in the LICENSE file that
0N/A * accompanied this code).
0N/A *
0N/A * You should have received a copy of the GNU General Public License version
0N/A * 2 along with this work; if not, write to the Free Software Foundation,
0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0N/A *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
0N/A */
0N/A
0N/Apackage javax.security.auth;
0N/A
0N/Aimport java.util.*;
0N/Aimport java.text.MessageFormat;
0N/Aimport java.security.Permission;
0N/Aimport java.security.PermissionCollection;
0N/Aimport java.security.Principal;
0N/Aimport sun.security.util.ResourcesMgr;
0N/A
0N/A/**
0N/A * This class is used to protect access to private Credentials
0N/A * belonging to a particular <code>Subject</code>. The <code>Subject</code>
0N/A * is represented by a Set of Principals.
0N/A *
0N/A * <p> The target name of this <code>Permission</code> specifies
0N/A * a Credential class name, and a Set of Principals.
0N/A * The only valid value for this Permission's actions is, "read".
0N/A * The target name must abide by the following syntax:
0N/A *
0N/A * <pre>
0N/A * CredentialClass {PrincipalClass "PrincipalName"}*
0N/A * </pre>
0N/A *
0N/A * For example, the following permission grants access to the
0N/A * com.sun.PrivateCredential owned by Subjects which have
0N/A * a com.sun.Principal with the name, "duke". Note that although
0N/A * this example, as well as all the examples below, do not contain
0N/A * Codebase, SignedBy, or Principal information in the grant statement
0N/A * (for simplicity reasons), actual policy configurations should
0N/A * specify that information when appropriate.
0N/A *
0N/A * <pre>
0N/A *
0N/A * grant {
0N/A * permission javax.security.auth.PrivateCredentialPermission
0N/A * "com.sun.PrivateCredential com.sun.Principal \"duke\"",
0N/A * "read";
0N/A * };
0N/A * </pre>
0N/A *
0N/A * If CredentialClass is "*", then access is granted to
0N/A * all private Credentials belonging to the specified
0N/A * <code>Subject</code>.
0N/A * If "PrincipalName" is "*", then access is granted to the
0N/A * specified Credential owned by any <code>Subject</code> that has the
0N/A * specified <code>Principal</code> (the actual PrincipalName doesn't matter).
0N/A * For example, the following grants access to the
0N/A * a.b.Credential owned by any <code>Subject</code> that has
0N/A * an a.b.Principal.
0N/A *
0N/A * <pre>
0N/A * grant {
0N/A * permission javax.security.auth.PrivateCredentialPermission
0N/A * "a.b.Credential a.b.Principal "*"",
0N/A * "read";
0N/A * };
0N/A * </pre>
0N/A *
0N/A * If both the PrincipalClass and "PrincipalName" are "*",
0N/A * then access is granted to the specified Credential owned by
0N/A * any <code>Subject</code>.
0N/A *
0N/A * <p> In addition, the PrincipalClass/PrincipalName pairing may be repeated:
0N/A *
0N/A * <pre>
0N/A * grant {
0N/A * permission javax.security.auth.PrivateCredentialPermission
0N/A * "a.b.Credential a.b.Principal "duke" c.d.Principal "dukette"",
0N/A * "read";
0N/A * };
0N/A * </pre>
0N/A *
0N/A * The above grants access to the private Credential, "a.b.Credential",
0N/A * belonging to a <code>Subject</code> with at least two associated Principals:
0N/A * "a.b.Principal" with the name, "duke", and "c.d.Principal", with the name,
0N/A * "dukette".
0N/A *
0N/A */
0N/Apublic final class PrivateCredentialPermission extends Permission {
0N/A
0N/A private static final long serialVersionUID = 5284372143517237068L;
0N/A
0N/A private static final CredOwner[] EMPTY_PRINCIPALS = new CredOwner[0];
0N/A
0N/A /**
0N/A * @serial
0N/A */
0N/A private String credentialClass;
0N/A
0N/A /**
0N/A * @serial The Principals associated with this permission.
0N/A * The set contains elements of type,
0N/A * <code>PrivateCredentialPermission.CredOwner</code>.
0N/A */
0N/A private Set principals; // ignored - kept around for compatibility
0N/A private transient CredOwner[] credOwners;
0N/A
0N/A /**
0N/A * @serial
0N/A */
0N/A private boolean testing = false;
0N/A
0N/A /**
0N/A * Create a new <code>PrivateCredentialPermission</code>
0N/A * with the specified <code>credentialClass</code> and Principals.
0N/A */
0N/A PrivateCredentialPermission(String credentialClass,
0N/A Set<Principal> principals) {
0N/A
0N/A super(credentialClass);
0N/A this.credentialClass = credentialClass;
0N/A
0N/A synchronized(principals) {
0N/A if (principals.size() == 0) {
0N/A this.credOwners = EMPTY_PRINCIPALS;
0N/A } else {
0N/A this.credOwners = new CredOwner[principals.size()];
0N/A int index = 0;
0N/A Iterator<Principal> i = principals.iterator();
0N/A while (i.hasNext()) {
0N/A Principal p = i.next();
0N/A this.credOwners[index++] = new CredOwner
0N/A (p.getClass().getName(),
0N/A p.getName());
0N/A }
0N/A }
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Creates a new <code>PrivateCredentialPermission</code>
0N/A * with the specified <code>name</code>. The <code>name</code>
0N/A * specifies both a Credential class and a <code>Principal</code> Set.
0N/A *
0N/A * <p>
0N/A *
0N/A * @param name the name specifying the Credential class and
0N/A * <code>Principal</code> Set. <p>
0N/A *
0N/A * @param actions the actions specifying that the Credential can be read.
0N/A *
0N/A * @throws IllegalArgumentException if <code>name</code> does not conform
0N/A * to the correct syntax or if <code>actions</code> is not "read".
0N/A */
0N/A public PrivateCredentialPermission(String name, String actions) {
0N/A super(name);
0N/A
0N/A if (!"read".equalsIgnoreCase(actions))
0N/A throw new IllegalArgumentException
3050N/A (ResourcesMgr.getString("actions.can.only.be.read."));
0N/A init(name);
0N/A }
0N/A
0N/A /**
0N/A * Returns the Class name of the Credential associated with this
0N/A * <code>PrivateCredentialPermission</code>.
0N/A *
0N/A * <p>
0N/A *
0N/A * @return the Class name of the Credential associated with this
0N/A * <code>PrivateCredentialPermission</code>.
0N/A */
0N/A public String getCredentialClass() {
0N/A return credentialClass;
0N/A }
0N/A
0N/A /**
0N/A * Returns the <code>Principal</code> classes and names
0N/A * associated with this <code>PrivateCredentialPermission</code>.
0N/A * The information is returned as a two-dimensional array (array[x][y]).
0N/A * The 'x' value corresponds to the number of <code>Principal</code>
0N/A * class and name pairs. When (y==0), it corresponds to
0N/A * the <code>Principal</code> class value, and when (y==1),
0N/A * it corresponds to the <code>Principal</code> name value.
0N/A * For example, array[0][0] corresponds to the class name of
0N/A * the first <code>Principal</code> in the array. array[0][1]
0N/A * corresponds to the <code>Principal</code> name of the
0N/A * first <code>Principal</code> in the array.
0N/A *
0N/A * <p>
0N/A *
0N/A * @return the <code>Principal</code> class and names associated
0N/A * with this <code>PrivateCredentialPermission</code>.
0N/A */
0N/A public String[][] getPrincipals() {
0N/A
0N/A if (credOwners == null || credOwners.length == 0) {
0N/A return new String[0][0];
0N/A }
0N/A
0N/A String[][] pArray = new String[credOwners.length][2];
0N/A for (int i = 0; i < credOwners.length; i++) {
0N/A pArray[i][0] = credOwners[i].principalClass;
0N/A pArray[i][1] = credOwners[i].principalName;
0N/A }
0N/A return pArray;
0N/A }
0N/A
0N/A /**
0N/A * Checks if this <code>PrivateCredentialPermission</code> implies
0N/A * the specified <code>Permission</code>.
0N/A *
0N/A * <p>
0N/A *
0N/A * This method returns true if:
0N/A * <p><ul>
0N/A * <li> <i>p</i> is an instanceof PrivateCredentialPermission and <p>
0N/A * <li> the target name for <i>p</i> is implied by this object's
0N/A * target name. For example:
0N/A * <pre>
0N/A * [* P1 "duke"] implies [a.b.Credential P1 "duke"].
0N/A * [C1 P1 "duke"] implies [C1 P1 "duke" P2 "dukette"].
0N/A * [C1 P2 "dukette"] implies [C1 P1 "duke" P2 "dukette"].
0N/A * </pre>
0N/A * </ul>
0N/A *
0N/A * <p>
0N/A *
0N/A * @param p the <code>Permission</code> to check against.
0N/A *
0N/A * @return true if this <code>PrivateCredentialPermission</code> implies
0N/A * the specified <code>Permission</code>, false if not.
0N/A */
0N/A public boolean implies(Permission p) {
0N/A
0N/A if (p == null || !(p instanceof PrivateCredentialPermission))
0N/A return false;
0N/A
0N/A PrivateCredentialPermission that = (PrivateCredentialPermission)p;
0N/A
0N/A if (!impliesCredentialClass(credentialClass, that.credentialClass))
0N/A return false;
0N/A
0N/A return impliesPrincipalSet(credOwners, that.credOwners);
0N/A }
0N/A
0N/A /**
0N/A * Checks two <code>PrivateCredentialPermission</code> objects for
0N/A * equality. Checks that <i>obj</i> is a
0N/A * <code>PrivateCredentialPermission</code>,
0N/A * and has the same credential class as this object,
0N/A * as well as the same Principals as this object.
0N/A * The order of the Principals in the respective Permission's
0N/A * target names is not relevant.
0N/A *
0N/A * <p>
0N/A *
0N/A * @param obj the object we are testing for equality with this object.
0N/A *
0N/A * @return true if obj is a <code>PrivateCredentialPermission</code>,
0N/A * has the same credential class as this object,
0N/A * and has the same Principals as this object.
0N/A */
0N/A public boolean equals(Object obj) {
0N/A if (obj == this)
0N/A return true;
0N/A
0N/A if (! (obj instanceof PrivateCredentialPermission))
0N/A return false;
0N/A
0N/A PrivateCredentialPermission that = (PrivateCredentialPermission)obj;
0N/A
0N/A return (this.implies(that) && that.implies(this));
0N/A }
0N/A
0N/A /**
0N/A * Returns the hash code value for this object.
0N/A *
0N/A * @return a hash code value for this object.
0N/A */
0N/A public int hashCode() {
0N/A return this.credentialClass.hashCode();
0N/A }
0N/A
0N/A /**
0N/A * Returns the "canonical string representation" of the actions.
0N/A * This method always returns the String, "read".
0N/A *
0N/A * <p>
0N/A *
0N/A * @return the actions (always returns "read").
0N/A */
0N/A public String getActions() {
0N/A return "read";
0N/A }
0N/A
0N/A /**
0N/A * Return a homogeneous collection of PrivateCredentialPermissions
0N/A * in a <code>PermissionCollection</code>.
0N/A * No such <code>PermissionCollection</code> is defined,
0N/A * so this method always returns <code>null</code>.
0N/A *
0N/A * <p>
0N/A *
0N/A * @return null in all cases.
0N/A */
0N/A public PermissionCollection newPermissionCollection() {
0N/A return null;
0N/A }
0N/A
0N/A private void init(String name) {
0N/A
0N/A if (name == null || name.trim().length() == 0) {
0N/A throw new IllegalArgumentException("invalid empty name");
0N/A }
0N/A
3381N/A ArrayList<CredOwner> pList = new ArrayList<>();
0N/A StringTokenizer tokenizer = new StringTokenizer(name, " ", true);
0N/A String principalClass = null;
0N/A String principalName = null;
0N/A
0N/A if (testing)
0N/A System.out.println("whole name = " + name);
0N/A
0N/A // get the Credential Class
0N/A credentialClass = tokenizer.nextToken();
0N/A if (testing)
0N/A System.out.println("Credential Class = " + credentialClass);
0N/A
0N/A if (tokenizer.hasMoreTokens() == false) {
0N/A MessageFormat form = new MessageFormat(ResourcesMgr.getString
3050N/A ("permission.name.name.syntax.invalid."));
0N/A Object[] source = {name};
0N/A throw new IllegalArgumentException
0N/A (form.format(source) + ResourcesMgr.getString
3050N/A ("Credential.Class.not.followed.by.a.Principal.Class.and.Name"));
0N/A }
0N/A
0N/A while (tokenizer.hasMoreTokens()) {
0N/A
0N/A // skip delimiter
0N/A tokenizer.nextToken();
0N/A
0N/A // get the Principal Class
0N/A principalClass = tokenizer.nextToken();
0N/A if (testing)
0N/A System.out.println(" Principal Class = " + principalClass);
0N/A
0N/A if (tokenizer.hasMoreTokens() == false) {
0N/A MessageFormat form = new MessageFormat(ResourcesMgr.getString
3050N/A ("permission.name.name.syntax.invalid."));
0N/A Object[] source = {name};
0N/A throw new IllegalArgumentException
0N/A (form.format(source) + ResourcesMgr.getString
3050N/A ("Principal.Class.not.followed.by.a.Principal.Name"));
0N/A }
0N/A
0N/A // skip delimiter
0N/A tokenizer.nextToken();
0N/A
0N/A // get the Principal Name
0N/A principalName = tokenizer.nextToken();
0N/A
0N/A if (!principalName.startsWith("\"")) {
0N/A MessageFormat form = new MessageFormat(ResourcesMgr.getString
3050N/A ("permission.name.name.syntax.invalid."));
0N/A Object[] source = {name};
0N/A throw new IllegalArgumentException
0N/A (form.format(source) + ResourcesMgr.getString
3050N/A ("Principal.Name.must.be.surrounded.by.quotes"));
0N/A }
0N/A
0N/A if (!principalName.endsWith("\"")) {
0N/A
0N/A // we have a name with spaces in it --
0N/A // keep parsing until we find the end quote,
0N/A // and keep the spaces in the name
0N/A
0N/A while (tokenizer.hasMoreTokens()) {
0N/A principalName = principalName + tokenizer.nextToken();
0N/A if (principalName.endsWith("\""))
0N/A break;
0N/A }
0N/A
0N/A if (!principalName.endsWith("\"")) {
0N/A MessageFormat form = new MessageFormat
0N/A (ResourcesMgr.getString
3050N/A ("permission.name.name.syntax.invalid."));
0N/A Object[] source = {name};
0N/A throw new IllegalArgumentException
0N/A (form.format(source) + ResourcesMgr.getString
3050N/A ("Principal.Name.missing.end.quote"));
0N/A }
0N/A }
0N/A
0N/A if (testing)
0N/A System.out.println("\tprincipalName = '" + principalName + "'");
0N/A
0N/A principalName = principalName.substring
0N/A (1, principalName.length() - 1);
0N/A
0N/A if (principalClass.equals("*") &&
0N/A !principalName.equals("*")) {
0N/A throw new IllegalArgumentException(ResourcesMgr.getString
3050N/A ("PrivateCredentialPermission.Principal.Class.can.not.be.a.wildcard.value.if.Principal.Name.is.not.a.wildcard.value"));
0N/A }
0N/A
0N/A if (testing)
0N/A System.out.println("\tprincipalName = '" + principalName + "'");
0N/A
0N/A pList.add(new CredOwner(principalClass, principalName));
0N/A }
0N/A
0N/A this.credOwners = new CredOwner[pList.size()];
0N/A pList.toArray(this.credOwners);
0N/A }
0N/A
0N/A private boolean impliesCredentialClass(String thisC, String thatC) {
0N/A
0N/A // this should never happen
0N/A if (thisC == null || thatC == null)
0N/A return false;
0N/A
0N/A if (testing)
0N/A System.out.println("credential class comparison: " +
0N/A thisC + "/" + thatC);
0N/A
0N/A if (thisC.equals("*"))
0N/A return true;
0N/A
0N/A /**
0N/A * XXX let's not enable this for now --
0N/A * if people want it, we'll enable it later
0N/A */
0N/A /*
0N/A if (thisC.endsWith("*")) {
0N/A String cClass = thisC.substring(0, thisC.length() - 2);
0N/A return thatC.startsWith(cClass);
0N/A }
0N/A */
0N/A
0N/A return thisC.equals(thatC);
0N/A }
0N/A
0N/A private boolean impliesPrincipalSet(CredOwner[] thisP, CredOwner[] thatP) {
0N/A
0N/A // this should never happen
0N/A if (thisP == null || thatP == null)
0N/A return false;
0N/A
0N/A if (thatP.length == 0)
0N/A return true;
0N/A
0N/A if (thisP.length == 0)
0N/A return false;
0N/A
0N/A for (int i = 0; i < thisP.length; i++) {
0N/A boolean foundMatch = false;
0N/A for (int j = 0; j < thatP.length; j++) {
0N/A if (thisP[i].implies(thatP[j])) {
0N/A foundMatch = true;
0N/A break;
0N/A }
0N/A }
0N/A if (!foundMatch) {
0N/A return false;
0N/A }
0N/A }
0N/A return true;
0N/A }
0N/A
0N/A /**
0N/A * Reads this object from a stream (i.e., deserializes it)
0N/A */
0N/A private void readObject(java.io.ObjectInputStream s) throws
0N/A java.io.IOException,
0N/A ClassNotFoundException {
0N/A
0N/A s.defaultReadObject();
0N/A
0N/A // perform new initialization from the permission name
0N/A
0N/A if (getName().indexOf(" ") == -1 && getName().indexOf("\"") == -1) {
0N/A
0N/A // name only has a credential class specified
0N/A credentialClass = getName();
0N/A credOwners = EMPTY_PRINCIPALS;
0N/A
0N/A } else {
0N/A
0N/A // perform regular initialization
0N/A init(getName());
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * @serial include
0N/A */
0N/A static class CredOwner implements java.io.Serializable {
0N/A
0N/A private static final long serialVersionUID = -5607449830436408266L;
0N/A
0N/A /**
0N/A * @serial
0N/A */
0N/A String principalClass;
0N/A /**
0N/A * @serial
0N/A */
0N/A String principalName;
0N/A
0N/A CredOwner(String principalClass, String principalName) {
0N/A this.principalClass = principalClass;
0N/A this.principalName = principalName;
0N/A }
0N/A
0N/A public boolean implies(Object obj) {
0N/A if (obj == null || !(obj instanceof CredOwner))
0N/A return false;
0N/A
0N/A CredOwner that = (CredOwner)obj;
0N/A
0N/A if (principalClass.equals("*") ||
0N/A principalClass.equals(that.principalClass)) {
0N/A
0N/A if (principalName.equals("*") ||
0N/A principalName.equals(that.principalName)) {
0N/A return true;
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * XXX no code yet to support a.b.*
0N/A */
0N/A
0N/A return false;
0N/A }
0N/A
0N/A public String toString() {
0N/A MessageFormat form = new MessageFormat(ResourcesMgr.getString
3050N/A ("CredOwner.Principal.Class.class.Principal.Name.name"));
0N/A Object[] source = {principalClass, principalName};
0N/A return (form.format(source));
0N/A }
0N/A }
0N/A}