/*
* @(#)PrivateCredentialPermission.java 1.31 03/12/19
*
* Copyright 2004 Sun Microsystems, Inc. All rights reserved.
* SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*/
package javax.security.auth;
import java.util.*;
import java.text.MessageFormat;
import java.security.Permission;
import java.security.PermissionCollection;
import java.security.Principal;
import sun.security.util.ResourcesMgr;
/**
* This class is used to protect access to private Credentials
* belonging to a particular Subject
. The Subject
* is represented by a Set of Principals.
*
*
The target name of this Permission
specifies
* a Credential class name, and a Set of Principals.
* The only valid value for this Permission's actions is, "read".
* The target name must abide by the following syntax:
*
*
* CredentialClass {PrincipalClass "PrincipalName"}* ** * For example, the following permission grants access to the * com.sun.PrivateCredential owned by Subjects which have * a com.sun.Principal with the name, "duke". Note that although * this example, as well as all the examples below, do not contain * Codebase, SignedBy, or Principal information in the grant statement * (for simplicity reasons), actual policy configurations should * specify that information when appropriate. * *
* * grant { * permission javax.security.auth.PrivateCredentialPermission * "com.sun.PrivateCredential com.sun.Principal \"duke\"", * "read"; * }; ** * If CredentialClass is "*", then access is granted to * all private Credentials belonging to the specified *
Subject
.
* If "PrincipalName" is "*", then access is granted to the
* specified Credential owned by any Subject
that has the
* specified Principal
(the actual PrincipalName doesn't matter).
* For example, the following grants access to the
* a.b.Credential owned by any Subject
that has
* an a.b.Principal.
*
* * grant { * permission javax.security.auth.PrivateCredentialPermission * "a.b.Credential a.b.Principal "*"", * "read"; * }; ** * If both the PrincipalClass and "PrincipalName" are "*", * then access is granted to the specified Credential owned by * any
Subject
.
*
* In addition, the PrincipalClass/PrincipalName pairing may be repeated: * *
* grant { * permission javax.security.auth.PrivateCredentialPermission * "a.b.Credential a.b.Principal "duke" c.d.Principal "dukette"", * "read"; * }; ** * The above grants access to the private Credential, "a.b.Credential", * belonging to a
Subject
with at least two associated Principals:
* "a.b.Principal" with the name, "duke", and "c.d.Principal", with the name,
* "dukette".
*
* @version 1.31, 12/19/03
*/
public final class PrivateCredentialPermission extends Permission {
private static final long serialVersionUID = 5284372143517237068L;
private static final CredOwner[] EMPTY_PRINCIPALS = new CredOwner[0];
/**
* @serial
*/
private String credentialClass;
/**
* @serial The Principals associated with this permission.
* The set contains elements of type,
* PrivateCredentialPermission.CredOwner
.
*/
private Set principals; // ignored - kept around for compatibility
private transient CredOwner[] credOwners;
/**
* @serial
*/
private boolean testing = false;
/**
* Create a new PrivateCredentialPermission
* with the specified credentialClass
and Principals.
*/
PrivateCredentialPermission(String credentialClass, Set principals) {
super(credentialClass);
this.credentialClass = credentialClass;
synchronized(principals) {
if (principals.size() == 0) {
this.credOwners = EMPTY_PRINCIPALS;
} else {
this.credOwners = new CredOwner[principals.size()];
int index = 0;
Iterator i = principals.iterator();
while (i.hasNext()) {
Principal p = (Principal)i.next();
this.credOwners[index++] = new CredOwner
(p.getClass().getName(),
p.getName());
}
}
}
}
/**
* Creates a new PrivateCredentialPermission
* with the specified name
. The name
* specifies both a Credential class and a Principal
Set.
*
*
*
* @param name the name specifying the Credential class and
* Principal
Set.
*
* @param actions the actions specifying that the Credential can be read.
*
* @throws IllegalArgumentException if name
does not conform
* to the correct syntax or if actions
is not "read".
*/
public PrivateCredentialPermission(String name, String actions) {
super(name);
if (!"read".equalsIgnoreCase(actions))
throw new IllegalArgumentException
(ResourcesMgr.getString("actions can only be 'read'"));
init(name);
}
/**
* Returns the Class name of the Credential associated with this
* PrivateCredentialPermission
.
*
*
*
* @return the Class name of the Credential associated with this
* PrivateCredentialPermission
.
*/
public String getCredentialClass() {
return credentialClass;
}
/**
* Returns the Principal
classes and names
* associated with this PrivateCredentialPermission
.
* The information is returned as a two-dimensional array (array[x][y]).
* The 'x' value corresponds to the number of Principal
* class and name pairs. When (y==0), it corresponds to
* the Principal
class value, and when (y==1),
* it corresponds to the Principal
name value.
* For example, array[0][0] corresponds to the class name of
* the first Principal
in the array. array[0][1]
* corresponds to the Principal
name of the
* first Principal
in the array.
*
*
*
* @return the Principal
class and names associated
* with this PrivateCredentialPermission
.
*/
public String[][] getPrincipals() {
if (credOwners == null || credOwners.length == 0) {
return new String[0][0];
}
String[][] pArray = new String[credOwners.length][2];
for (int i = 0; i < credOwners.length; i++) {
pArray[i][0] = credOwners[i].principalClass;
pArray[i][1] = credOwners[i].principalName;
}
return pArray;
}
/**
* Checks if this PrivateCredentialPermission
implies
* the specified Permission
.
*
*
* * This method returns true if: *
*
* [* P1 "duke"] implies [a.b.Credential P1 "duke"]. * [C1 P1 "duke"] implies [C1 P1 "duke" P2 "dukette"]. * [C1 P2 "dukette"] implies [C1 P1 "duke" P2 "dukette"]. **
*
* @param p the Permission
to check against.
*
* @return true if this PrivateCredentialPermission
implies
* the specified Permission
, false if not.
*/
public boolean implies(Permission p) {
if (p == null || !(p instanceof PrivateCredentialPermission))
return false;
PrivateCredentialPermission that = (PrivateCredentialPermission)p;
if (!impliesCredentialClass(credentialClass, that.credentialClass))
return false;
return impliesPrincipalSet(credOwners, that.credOwners);
}
/**
* Checks two PrivateCredentialPermission
objects for
* equality. Checks that obj is a
* PrivateCredentialPermission
,
* and has the same credential class as this object,
* as well as the same Principals as this object.
* The order of the Principals in the respective Permission's
* target names is not relevant.
*
*
*
* @param obj the object we are testing for equality with this object.
*
* @return true if obj is a PrivateCredentialPermission
,
* has the same credential class as this object,
* and has the same Principals as this object.
*/
public boolean equals(Object obj) {
if (obj == this)
return true;
if (! (obj instanceof PrivateCredentialPermission))
return false;
PrivateCredentialPermission that = (PrivateCredentialPermission)obj;
return (this.implies(that) && that.implies(this));
}
/**
* Returns the hash code value for this object.
*
* @return a hash code value for this object.
*/
public int hashCode() {
return this.credentialClass.hashCode();
}
/**
* Returns the "canonical string representation" of the actions.
* This method always returns the String, "read".
*
*
*
* @return the actions (always returns "read").
*/
public String getActions() {
return "read";
}
/**
* Return a homogeneous collection of PrivateCredentialPermissions
* in a PermissionCollection
.
* No such PermissionCollection
is defined,
* so this method always returns null
.
*
*
* * @return null in all cases. */ public PermissionCollection newPermissionCollection() { return null; } private void init(String name) { if (name == null || name.trim().length() == 0) { throw new IllegalArgumentException("invalid empty name"); } ArrayList pList = new ArrayList(); StringTokenizer tokenizer = new StringTokenizer(name, " ", true); String principalClass = null; String principalName = null; if (testing) System.out.println("whole name = " + name); // get the Credential Class credentialClass = tokenizer.nextToken(); if (testing) System.out.println("Credential Class = " + credentialClass); if (tokenizer.hasMoreTokens() == false) { MessageFormat form = new MessageFormat(ResourcesMgr.getString ("permission name [name] syntax invalid: ")); Object[] source = {name}; throw new IllegalArgumentException (form.format(source) + ResourcesMgr.getString ("Credential Class not followed by a " + "Principal Class and Name")); } while (tokenizer.hasMoreTokens()) { // skip delimiter tokenizer.nextToken(); // get the Principal Class principalClass = tokenizer.nextToken(); if (testing) System.out.println(" Principal Class = " + principalClass); if (tokenizer.hasMoreTokens() == false) { MessageFormat form = new MessageFormat(ResourcesMgr.getString ("permission name [name] syntax invalid: ")); Object[] source = {name}; throw new IllegalArgumentException (form.format(source) + ResourcesMgr.getString ("Principal Class not followed by a Principal Name")); } // skip delimiter tokenizer.nextToken(); // get the Principal Name principalName = tokenizer.nextToken(); if (!principalName.startsWith("\"")) { MessageFormat form = new MessageFormat(ResourcesMgr.getString ("permission name [name] syntax invalid: ")); Object[] source = {name}; throw new IllegalArgumentException (form.format(source) + ResourcesMgr.getString ("Principal Name must be surrounded by quotes")); } if (!principalName.endsWith("\"")) { // we have a name with spaces in it -- // keep parsing until we find the end quote, // and keep the spaces in the name while (tokenizer.hasMoreTokens()) { principalName = principalName + tokenizer.nextToken(); if (principalName.endsWith("\"")) break; } if (!principalName.endsWith("\"")) { MessageFormat form = new MessageFormat (ResourcesMgr.getString ("permission name [name] syntax invalid: ")); Object[] source = {name}; throw new IllegalArgumentException (form.format(source) + ResourcesMgr.getString ("Principal Name missing end quote")); } } if (testing) System.out.println("\tprincipalName = '" + principalName + "'"); principalName = principalName.substring (1, principalName.length() - 1); if (principalClass.equals("*") && !principalName.equals("*")) { throw new IllegalArgumentException(ResourcesMgr.getString ("PrivateCredentialPermission Principal Class " + "can not be a wildcard (*) value if Principal Name " + "is not a wildcard (*) value")); } if (testing) System.out.println("\tprincipalName = '" + principalName + "'"); pList.add(new CredOwner(principalClass, principalName)); } this.credOwners = new CredOwner[pList.size()]; pList.toArray((CredOwner[])this.credOwners); } private boolean impliesCredentialClass(String thisC, String thatC) { // this should never happen if (thisC == null || thatC == null) return false; if (testing) System.out.println("credential class comparison: " + thisC + "/" + thatC); if (thisC.equals("*")) return true; /** * XXX let's not enable this for now -- * if people want it, we'll enable it later */ /* if (thisC.endsWith("*")) { String cClass = thisC.substring(0, thisC.length() - 2); return thatC.startsWith(cClass); } */ return thisC.equals(thatC); } private boolean impliesPrincipalSet(CredOwner[] thisP, CredOwner[] thatP) { // this should never happen if (thisP == null || thatP == null) return false; if (thatP.length == 0) return true; if (thisP.length == 0) return false; for (int i = 0; i < thisP.length; i++) { boolean foundMatch = false; for (int j = 0; j < thatP.length; j++) { if (thisP[i].implies(thatP[j])) { foundMatch = true; break; } } if (!foundMatch) { return false; } } return true; } /** * Reads this object from a stream (i.e., deserializes it) */ private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException { s.defaultReadObject(); // perform new initialization from the permission name if (getName().indexOf(" ") == -1 && getName().indexOf("\"") == -1) { // name only has a credential class specified credentialClass = getName(); credOwners = EMPTY_PRINCIPALS; } else { // perform regular initialization init(getName()); } } /** * @serial include */ static class CredOwner implements java.io.Serializable { private static final long serialVersionUID = -5607449830436408266L; /** * @serial */ String principalClass; /** * @serial */ String principalName; CredOwner(String principalClass, String principalName) { this.principalClass = principalClass; this.principalName = principalName; } public boolean implies(Object obj) { if (obj == null || !(obj instanceof CredOwner)) return false; CredOwner that = (CredOwner)obj; if (principalClass.equals("*") || principalClass.equals(that.principalClass)) { if (principalName.equals("*") || principalName.equals(that.principalName)) { return true; } } /** * XXX no code yet to support a.b.* */ return false; } public String toString() { MessageFormat form = new MessageFormat(ResourcesMgr.getString ("CredOwner:\n\tPrincipal Class = class\n\t" + "Principal Name = name")); Object[] source = {principalClass, principalName}; return (form.format(source)); } } }