FileDocCategorySizeDatePackage
SubjectDomainCombiner.javaAPI DocJava SE 5 API17239Fri Aug 26 14:57:46 BST 2005javax.security.auth

SubjectDomainCombiner

public class SubjectDomainCombiner extends Object implements DomainCombiner
A SubjectDomainCombiner updates ProtectionDomains with Principals from the Subject associated with this SubjectDomainCombiner.
version
1.47, 05/27/05

Fields Summary
private Subject
subject
private WeakKeyValueMap
cachedPDs
private Set
principalSet
private Principal[]
principals
private static final Debug
debug
private static final boolean
useJavaxPolicy
private static final boolean
allowCaching
Constructors Summary
public SubjectDomainCombiner(Subject subject)
Associate the provided Subject with this SubjectDomainCombiner.

param
subject the Subject to be associated with with this SubjectDomainCombiner.


                    		       
       
	this.subject = subject;

	if (subject.isReadOnly()) {
	    principalSet = subject.getPrincipals();
	    principals = (Principal[])principalSet.toArray
			(new Principal[principalSet.size()]);
	}
    
Methods Summary
private static booleancachePolicy()

	String s = (String)AccessController.doPrivileged
	    (new PrivilegedAction() {
	    public Object run() {
		return java.security.Security.getProperty
					("cache.auth.policy");
	    }
	});
	if (s != null) {
	    Boolean b = new Boolean(s); 
	    return b.booleanValue(); 
	}

	// cache by default
	return true;
    
public java.security.ProtectionDomain[]combine(java.security.ProtectionDomain[] currentDomains, java.security.ProtectionDomain[] assignedDomains)
Update the relevant ProtectionDomains with the Principals from the Subject associated with this SubjectDomainCombiner.

A new ProtectionDomain instance is created for each ProtectionDomain in the currentDomains array. Each new ProtectionDomain instance is created using the CodeSource, Permissions and ClassLoader from the corresponding ProtectionDomain in currentDomains, as well as with the Principals from the Subject associated with this SubjectDomainCombiner.

All of the newly instantiated ProtectionDomains are combined into a new array. The ProtectionDomains from the assignedDomains array are appended to this new array, and the result is returned.

Note that optimizations such as the removal of duplicate ProtectionDomains may have occurred. In addition, caching of ProtectionDomains may be permitted.

param
currentDomains the ProtectionDomains associated with the current execution Thread, up to the most recent privileged ProtectionDomain. The ProtectionDomains are are listed in order of execution, with the most recently executing ProtectionDomain residing at the beginning of the array. This parameter may be null if the current execution Thread has no associated ProtectionDomains.

param
assignedDomains the ProtectionDomains inherited from the parent Thread, or the ProtectionDomains from the privileged context, if a call to AccessController.doPrivileged(..., context) had occurred This parameter may be null if there were no ProtectionDomains inherited from the parent Thread, or from the privileged context.
return
a new array consisting of the updated ProtectionDomains, or null.

	if (debug != null) {
	    if (subject == null) {
		debug.println("null subject");
	    } else {
		final Subject s = subject;
		AccessController.doPrivileged
		    (new java.security.PrivilegedAction() {
		    public Object run() {
			debug.println(s.toString());
			return null;
		    }
		});
	    }
	    printInputDomains(currentDomains, assignedDomains);
	}

	if (currentDomains == null || currentDomains.length == 0) {
	    // No need to optimize assignedDomains because it should
	    // have been previously optimized (when it was set).

	    // Note that we are returning a direct reference
	    // to the input array - since ACC does not clone
	    // the arrays when it calls combiner.combine,
	    // multiple ACC instances may share the same
	    // array instance in this case

	    return assignedDomains;
	}

	// optimize currentDomains
	//
	// No need to optimize assignedDomains because it should
        // have been previously optimized (when it was set).

	currentDomains = optimize(currentDomains);
	if (debug != null) {
	    debug.println("after optimize");
	    printInputDomains(currentDomains, assignedDomains);
	}

	if (currentDomains == null && assignedDomains == null) {
	    return null;
	}

	// maintain backwards compatibility for people who provide
	// their own javax.security.auth.Policy implementations
	if (useJavaxPolicy) {
	    return combineJavaxPolicy(currentDomains, assignedDomains);
	}
	
	int cLen = (currentDomains == null ? 0 : currentDomains.length);
	int aLen = (assignedDomains == null ? 0 : assignedDomains.length);

	// the ProtectionDomains for the new AccessControlContext
	// that we will return
	ProtectionDomain[] newDomains = new ProtectionDomain[cLen + aLen];

	boolean allNew = true;
	synchronized(cachedPDs) {
	    if (!subject.isReadOnly() &&
		!subject.getPrincipals().equals(principalSet)) {

		// if the Subject was mutated, clear the PD cache
		Set newSet = subject.getPrincipals();
		synchronized(newSet) {
		    principalSet = new java.util.HashSet(newSet);
		}
		principals = (Principal[])principalSet.toArray
			(new Principal[principalSet.size()]);
		cachedPDs.clear();

		if (debug != null) {
		    debug.println("Subject mutated - clearing cache");
		}
	    } 

	    ProtectionDomain subjectPd;
	    for (int i = 0; i < cLen; i++) {
		ProtectionDomain pd = currentDomains[i];

		subjectPd = cachedPDs.getValue(pd);

		if (subjectPd == null) {
		    subjectPd = new ProtectionDomain(pd.getCodeSource(),
						pd.getPermissions(), 
						pd.getClassLoader(),
						principals);
		    cachedPDs.putValue(pd, subjectPd);
		} else {
		    allNew = false;
		}
		newDomains[i] = subjectPd;
	    }
        }

	if (debug != null) {
	    debug.println("updated current: "); 
	    for (int i = 0; i < cLen; i++) {
		debug.println("\tupdated[" + i + "] = " +
				printDomain(newDomains[i]));
	    }
	}

	// now add on the assigned domains
	if (aLen > 0) {
	    System.arraycopy(assignedDomains, 0, newDomains, cLen, aLen);

	    // optimize the result (cached PDs might exist in assignedDomains)
	    if (!allNew) {
		newDomains = optimize(newDomains);
	    }
	}

	// if aLen == 0 || allNew, no need to further optimize newDomains
	
	if (debug != null) {
	    if (newDomains == null || newDomains.length == 0) {
		debug.println("returning null");
	    } else {
		debug.println("combinedDomains: ");
		for (int i = 0; i < newDomains.length; i++) {
		    debug.println("newDomain " + i + ": " +
				  printDomain(newDomains[i]));
		}
	    }
	}
	
	// return the new ProtectionDomains
	if (newDomains == null || newDomains.length == 0) {
	    return null;
	} else {
	    return newDomains;
	}
    
private java.security.ProtectionDomain[]combineJavaxPolicy(java.security.ProtectionDomain[] currentDomains, java.security.ProtectionDomain[] assignedDomains)
Use the javax.security.auth.Policy implementation


	if (!allowCaching) {
	    java.security.AccessController.doPrivileged
		(new PrivilegedAction() {
		    public Object run() {
			// Call refresh only caching is disallowed
			javax.security.auth.Policy.getPolicy().refresh();
			return null;
		    }
		});
	}
	
	int cLen = (currentDomains == null ? 0 : currentDomains.length);
	int aLen = (assignedDomains == null ? 0 : assignedDomains.length);

	// the ProtectionDomains for the new AccessControlContext
	// that we will return
	ProtectionDomain[] newDomains = new ProtectionDomain[cLen + aLen];

	synchronized(cachedPDs) {
	    if (!subject.isReadOnly() &&
		!subject.getPrincipals().equals(principalSet)) {

		// if the Subject was mutated, clear the PD cache
		Set newSet = subject.getPrincipals();
		synchronized(newSet) {
		    principalSet = new java.util.HashSet(newSet);
		}
		principals = (Principal[])principalSet.toArray
			(new Principal[principalSet.size()]);
		cachedPDs.clear();

		if (debug != null) {
		    debug.println("Subject mutated - clearing cache");
		}
	    }

	    for (int i = 0; i < cLen; i++) {
		ProtectionDomain pd = currentDomains[i];
		ProtectionDomain subjectPd = cachedPDs.getValue(pd);

		if (subjectPd == null) {

		    // XXX 
		    // we must first add the original permissions.
		    // that way when we later add the new JAAS permissions,
		    // any unresolved JAAS-related permissions will
		    // automatically get resolved.

		    // get the original perms
		    Permissions perms = new Permissions();
		    PermissionCollection coll = pd.getPermissions();
		    java.util.Enumeration e;
		    synchronized (coll) {
			e = coll.elements();
			while (e.hasMoreElements()) {
			    Permission newPerm = (Permission)e.nextElement();
			    perms.add(newPerm);
			}
		    }

		    // get perms from the policy

		    final java.security.CodeSource finalCs = pd.getCodeSource();
		    final Subject finalS = subject;
		    PermissionCollection newPerms = (PermissionCollection)
			java.security.AccessController.doPrivileged
			(new PrivilegedAction() {
			public Object run() {
			  return
			  javax.security.auth.Policy.getPolicy().getPermissions
				(finalS, finalCs);
			}
		    });
			
		    // add the newly granted perms,
		    // avoiding duplicates
		    synchronized (newPerms) {
			e = newPerms.elements();
			while (e.hasMoreElements()) {
			    Permission newPerm = (Permission)e.nextElement();
			    if (!perms.implies(newPerm)) {
				perms.add(newPerm);
				if (debug != null) 
				    debug.println (
					"Adding perm " + newPerm + "\n");
			    }
			}
		    }
		    subjectPd = new ProtectionDomain(finalCs, perms);

		    if (allowCaching)
			cachedPDs.putValue(pd, subjectPd);
		}
		newDomains[i] = subjectPd;
	    }
	}

	if (debug != null) {
	    debug.println("updated current: ");
	    for (int i = 0; i < cLen; i++) {
		debug.println("\tupdated[" + i + "] = " + newDomains[i]);
	    }
	}

	// now add on the assigned domains
	if (aLen > 0) {
	    System.arraycopy(assignedDomains, 0, newDomains, cLen, aLen);
	}

	if (debug != null) {
	    if (newDomains == null || newDomains.length == 0) {
		debug.println("returning null");
	    } else {
		debug.println("combinedDomains: ");
		for (int i = 0; i < newDomains.length; i++) {
		    debug.println("newDomain " + i + ": " +
			newDomains[i].toString());
		}
	    }
	}

	// return the new ProtectionDomains
	if (newDomains == null || newDomains.length == 0) {
	    return null;
	} else {
	    return newDomains;
	}
    
private static booleancompatPolicy()

	javax.security.auth.Policy javaxPolicy =
	    (javax.security.auth.Policy)AccessController.doPrivileged
	    (new PrivilegedAction() {
	    public Object run() {
		return javax.security.auth.Policy.getPolicy();
	    }
	});

	if (!(javaxPolicy instanceof com.sun.security.auth.PolicyFile)) {
	    if (debug != null) {
		debug.println("Providing backwards compatibility for " +
			"javax.security.auth.policy implementation: " +
			javaxPolicy.toString());
	    }

	    return true;
	} else {
	    return false;
	}
    
public javax.security.auth.SubjectgetSubject()
Get the Subject associated with this SubjectDomainCombiner.

return
the Subject associated with this SubjectDomainCombiner, or null if no Subject is associated with this SubjectDomainCombiner.
exception
SecurityException if the caller does not have permission to get the Subject associated with this SubjectDomainCombiner.

	java.lang.SecurityManager sm = System.getSecurityManager();
	if (sm != null) {
	    sm.checkPermission(new AuthPermission
		("getSubjectFromDomainCombiner"));
	}
	return subject;
    
private static java.security.ProtectionDomain[]optimize(java.security.ProtectionDomain[] domains)

	if (domains == null || domains.length == 0)
	    return null;

	ProtectionDomain[] optimized = new ProtectionDomain[domains.length];
	ProtectionDomain pd;
	int num = 0;
	for (int i = 0; i < domains.length; i++) {

	    // skip domains with AllPermission 
	    // XXX
	    //
	    //	if (domains[i].implies(ALL_PERMISSION))
	    //	continue;

	    // skip System Domains
	    if ((pd = domains[i]) != null) {

		// remove duplicates
		boolean found = false;
		for (int j = 0; j < num && !found; j++) {
		    found = (optimized[j] == pd);
		}
		if (!found) {
		    optimized[num++] = pd;
		}
	    }
	}

	// resize the array if necessary
	if (num > 0 && num < domains.length) {
	    ProtectionDomain[] downSize = new ProtectionDomain[num];
	    System.arraycopy(optimized, 0, downSize, 0, downSize.length);
	    optimized = downSize;
	}

	return ((num == 0 || optimized.length == 0) ? null : optimized);
    
private static java.lang.StringprintDomain(java.security.ProtectionDomain pd)

	if (pd == null) {
	    return "null";
	}
	return (String)AccessController.doPrivileged(new PrivilegedAction() {
	    public Object run() {
		return pd.toString();
	    }
	});
    
private static voidprintInputDomains(java.security.ProtectionDomain[] currentDomains, java.security.ProtectionDomain[] assignedDomains)

	if (currentDomains == null || currentDomains.length == 0) {
	    debug.println("currentDomains null or 0 length");
	} else {
	    for (int i = 0; currentDomains != null &&
			i < currentDomains.length; i++) {
		if (currentDomains[i] == null) {
		    debug.println("currentDomain " + i + ": SystemDomain");
		} else {
		    debug.println("currentDomain " + i + ": " +
				printDomain(currentDomains[i]));
		}
	    }
	}

	if (assignedDomains == null || assignedDomains.length == 0) {
	    debug.println("assignedDomains null or 0 length");
	} else {
	    debug.println("assignedDomains = ");
	    for (int i = 0; assignedDomains != null &&
			i < assignedDomains.length; i++) {
		if (assignedDomains[i] == null) {
		    debug.println("assignedDomain " + i + ": SystemDomain");
		} else {
		    debug.println("assignedDomain " + i + ": " +
				printDomain(assignedDomains[i]));
		}
	    }
	}