Modified: river/jtsk/skunk/peterConcurrentPolicy/src/net/jini/security/policy/DynamicPolicyProvider.java URL: http://svn.apache.org/viewvc/river/jtsk/skunk/peterConcurrentPolicy/src/net/jini/security/policy/DynamicPolicyProvider.java?rev=1225993&r1=1225992&r2=1225993&view=diff ============================================================================== --- river/jtsk/skunk/peterConcurrentPolicy/src/net/jini/security/policy/DynamicPolicyProvider.java (original) +++ river/jtsk/skunk/peterConcurrentPolicy/src/net/jini/security/policy/DynamicPolicyProvider.java Sat Dec 31 00:13:00 2011 @@ -21,6 +21,7 @@ package net.jini.security.policy; import java.io.IOException; import java.lang.ref.Reference; import java.rmi.RemoteException; +import java.security.PrivilegedActionException; import org.apache.river.api.security.DelegateSecurityManager; import java.security.AccessController; import java.security.AllPermission; @@ -32,6 +33,7 @@ import java.security.Permissions; import java.security.Policy; import java.security.Principal; import java.security.PrivilegedAction; +import java.security.PrivilegedExceptionAction; import java.security.ProtectionDomain; import java.security.Security; import java.util.ArrayList; @@ -43,15 +45,22 @@ import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Set; +import java.util.TreeSet; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReadWriteLock; +import java.util.concurrent.locks.ReentrantLock; +import java.util.concurrent.locks.ReentrantReadWriteLock; import java.util.logging.Level; import java.util.logging.Logger; import net.jini.security.GrantPermission; +import net.jini.security.PermissionComparator; import org.apache.river.api.security.PermissionGrant; import org.apache.river.api.security.PermissionGrantBuilder; import org.apache.river.api.security.policy.RemotePolicy; -import org.apache.river.api.security.RevokePermission; +import org.apache.river.api.security.PolicyPermission; import org.apache.river.api.security.policy.RevokeableDynamicPolicy; import org.apache.river.impl.security.policy.util.PolicyUtils; import org.apache.river.impl.util.CollectionsConcurrent; @@ -162,8 +171,8 @@ public class DynamicPolicyProvider exten private static final String basePolicyClassProperty = "net.jini.security.policy.DynamicPolicyProvider.basePolicyClass"; private static final String defaultBasePolicyClass = -// "net.jini.security.policy.ConcurrentPolicyFile"; - "net.jini.security.policy.PolicyFileProvider"; + "net.jini.security.policy.ConcurrentPolicyFile"; +// "net.jini.security.policy.PolicyFileProvider"; private static final ProtectionDomain sysDomain = AccessController.doPrivileged(new PrivilegedAction<ProtectionDomain>() { @@ -186,15 +195,14 @@ public class DynamicPolicyProvider exten private volatile PermissionGrant[] remotePolicyGrants; // Write protected by grantLock. /* This lock protects write updating of remotePolicyGrants reference */ private final Object grantLock; - private final Policy basePolicy; // final looks after its own sync + private final Policy basePolicy; // refresh protected by transactionWriteLock /* cache of ProtectionDomain and their Permissions */ - private final ConcurrentMap<ProtectionDomain, PermissionCollection> cache; - /* A cache of Permission's for each PermissionGrant, this avoids a mutating - * PermissionGrant implementation from escallating permissions, this - * cache should be updated when receiving PermissionGrant and checking - * the callers Permissions. The current implementation uses a weak identity - * map that cleans itself. */ - private final ConcurrentMap<PermissionGrant, Permission[]> grantCache; + private final ConcurrentMap<ProtectionDomain, PermissionCollection> cache; // protected by transactionWriteLock + /* A transaction ID to avoid updating the cache with old information + * after it has been cleared */ + private final Lock transactionWriteLock; // Lock to protect cache clear and transactionID write. + private final Lock transactionReadLock; // Lock to protect cache put and transactionID reads. + private int transactionID; // Protected by transaction locks // DynamicPolicy grant's for Proxy's. private final Collection<PermissionGrant> dynamicPolicyGrants; private final boolean basePolicyIsDynamic; // Don't use cache if true. @@ -206,6 +214,7 @@ public class DynamicPolicyProvider exten // avoid dead locks due to bug 4911907 private final Guard revokePermission; + private final Permission implementsPermissionGrant; private final Guard protectionDomainPermission; /** @@ -275,12 +284,10 @@ public class DynamicPolicyProvider exten ConcurrentMap<Referrer<ProtectionDomain>, Referrer<PermissionCollection>> internal = new ConcurrentHashMap<Referrer<ProtectionDomain>,Referrer<PermissionCollection>>(120); cache = RC.concurrentMap(internal, Ref.WEAK_IDENTITY, Ref.SOFT); - ConcurrentMap<Referrer<PermissionGrant>, Referrer<Permission[]>> gInternal - = new ConcurrentHashMap<Referrer<PermissionGrant>, Referrer<Permission[]>>(60); - grantCache = RC.concurrentMap(gInternal, Ref.WEAK, Ref.STRONG); loggable = logger.isLoggable(Level.FINEST); grantLock = new Object(); - revokePermission = new RevokePermission(); + revokePermission = new PolicyPermission("REVOKE"); + implementsPermissionGrant = new PolicyPermission("implementPermissionGrant"); protectionDomainPermission = new RuntimePermission("getProtectionDomain"); if (basePolicy instanceof DynamicPolicy) { DynamicPolicy dp = (DynamicPolicy) basePolicy; @@ -300,6 +307,10 @@ public class DynamicPolicyProvider exten } else { basePolicyIsRemote = false; } + transactionID = 0; + ReadWriteLock rwl = new ReentrantReadWriteLock(); + transactionWriteLock = rwl.writeLock(); + transactionReadLock = rwl.readLock(); ensureDependenciesResolved(); } @@ -320,12 +331,10 @@ public class DynamicPolicyProvider exten ConcurrentMap<Referrer<ProtectionDomain>, Referrer<PermissionCollection>> internal = new ConcurrentHashMap<Referrer<ProtectionDomain>,Referrer<PermissionCollection>>(120); cache = RC.concurrentMap(internal, Ref.WEAK_IDENTITY, Ref.SOFT); - ConcurrentMap<Referrer<PermissionGrant>, Referrer<Permission[]>> gInternal - = new ConcurrentHashMap<Referrer<PermissionGrant>, Referrer<Permission[]>>(60); - grantCache = RC.concurrentMap(gInternal, Ref.WEAK, Ref.STRONG); loggable = logger.isLoggable(Level.FINEST); grantLock = new Object(); - revokePermission = new RevokePermission(); + revokePermission = new PolicyPermission("REVOKE"); + implementsPermissionGrant = new PolicyPermission("implementPermissionGrant"); protectionDomainPermission = new RuntimePermission("getProtectionDomain"); if (basePolicy instanceof DynamicPolicy) { DynamicPolicy dp = (DynamicPolicy) basePolicy; @@ -345,6 +354,10 @@ public class DynamicPolicyProvider exten } else { basePolicyIsRemote = false; } + transactionID = 0; + ReadWriteLock rwl = new ReentrantReadWriteLock(); + transactionWriteLock = rwl.writeLock(); + transactionReadLock = rwl.readLock(); ensureDependenciesResolved(); } @@ -434,11 +447,11 @@ Put the policy providers and all referen PermissionGrant p = dynamicGrants.next(); if ( p.implies(codesource, null) ){ // Only use the trusted grantCache. - Permission[] perm = grantCache.get(p); - int s = perm.length; - for ( int j = 0; j < s; j++){ - permissions.add(perm[j]); - } + Collection<Permission> perms = p.getPermissions(); + Iterator<Permission> it = perms.iterator(); + while (it.hasNext()){ + permissions.add(it.next()); + } } } return permissions; @@ -464,22 +477,16 @@ Put the policy providers and all referen * TODO: Remove PolicyPermission's */ PermissionCollection pc = basePolicy.getPermissions(domain); - PermissionCollection permissions = new Permissions(); - Enumeration<Permission> enu = pc.elements(); - while (enu.hasMoreElements()){ - permissions.add(enu.nextElement()); - } + pc = PolicyUtils.asConcurrent(pc); PermissionGrant [] grantsRefCopy = remotePolicyGrants; // Interim updates not seen. int l = grantsRefCopy.length; for ( int i = 0; i < l; i++ ){ if ( grantsRefCopy[i].implies(domain) ){ - // Only use the trusted grantCache. - Permission[] perm = grantCache.get(grantsRefCopy[i]); - int s = perm.length; - for ( int j = 0; j < s; j++){ - PolicyPermission pp = new PolicyPermission(perm[j]); - permissions.add(pp); - } + Collection<Permission> perms = grantsRefCopy[i].getPermissions(); + Iterator<Permission> it = perms.iterator(); + while (it.hasNext()){ + pc.add(it.next()); + } } } Iterator<PermissionGrant> dynamicGrants = dynamicPolicyGrants.iterator(); @@ -487,20 +494,14 @@ Put the policy providers and all referen PermissionGrant p = dynamicGrants.next(); if ( p.implies(domain) ){ // Only use the trusted grantCache. - Permission[] perm = grantCache.get(p); - int s = perm.length; - for ( int j = 0; j < s; j++){ - Permission pp = null; - if (revokeable) { - pp = new PolicyPermission(perm[j]); - }else{ - pp = perm[j]; - } - permissions.add(pp); - } + Collection<Permission> perms = p.getPermissions(); + Iterator<Permission> it = perms.iterator(); + while (it.hasNext()){ + pc.add(it.next()); + } } } - return permissions; + return pc; } /* River-26 Mark Brouwer suggested making UmbrellaPermission's expandable @@ -518,9 +519,12 @@ Put the policy providers and all referen } if (permission == null) throw new NullPointerException("permission not allowed to be null"); // First check our cache if the basePolicy is not dynamic. + PermissionCollection pc = domain != null? cache.get(domain): null; if ( pc != null ) { - if (pc.implies(permission)) return true; + /* Out of date cache is cleared and only updated with the latest + * grants don't bother retrieving it again */ + if ( pc.implies(permission) ) return true; } Thread thread = Thread.currentThread(); if (thread.isInterrupted()) return false; @@ -529,7 +533,16 @@ Put the policy providers and all referen * while another Permission within that collection is already * resolved, the Enumeration will cause a ConcurrentModificationException. */ - PermissionCollection bpc = basePolicy.getPermissions(domain); + int currentTransactionID; + PermissionCollection bpc = null; + transactionReadLock.lock(); + try { + currentTransactionID = transactionID; + bpc = basePolicy.getPermissions(domain); + }finally{ + transactionReadLock.unlock(); + } + /* Be mindful of static Permissions held by the * ProtectionDomain, a Permission may be implied by the * the combination of Permission's in the ProtectionDomain and @@ -556,31 +569,17 @@ Put the policy providers and all referen pc = PolicyUtils.asConcurrent(bpc); /* Don't place it in the cache half finished or check it yet since * mutations are blocking */ -// PermissionCollection existed = -// domain != null ? cache.putIfAbsent(domain, pc): null; -// if ( existed != null ){ -// pc = existed; -// } -// expandUmbrella(pc); // We need to avoid using PolicyFileProvider as grants from it are not revokable. -// if ( pc.implies(permission)) return true; - - // Once we get to here pc is definitely not null and we have the - // copy referenced in the cache. -// if (loggable){ -// logger.log(Level.FINEST, domain + permission.toString() + -// ": Base policy is not dynamic and returned false" ); -// } - // If the base policy doesn't imply a Permission then we should check for dynamic grants - Collection<Permission> dynamicallyGrantedPermissions = new HashSet<Permission>(120); - PermissionGrant[] grantsRefCopy = remotePolicyGrants; // In case the grants volatile reference is updated. - + PermissionGrant[] grantsRefCopy = remotePolicyGrants; // In case the grants volatile reference is updated. if (thread.isInterrupted()) return false; int l = grantsRefCopy.length; for ( int i = 0; i < l; i++){ if (grantsRefCopy[i].implies(domain)) { // We only trust grantCache in case of mutable PermissionGrant. - Permission[] perms = grantCache.get(grantsRefCopy[i]); - dynamicallyGrantedPermissions.addAll(Arrays.asList(perms)); + Collection<Permission> perms = grantsRefCopy[i].getPermissions(); + Iterator<Permission> it = perms.iterator(); + while (it.hasNext()){ + pc.add(it.next()); + } } } if (thread.isInterrupted()) return false; @@ -588,36 +587,27 @@ Put the policy providers and all referen while (grants.hasNext()){ PermissionGrant g = grants.next(); if (g.implies(domain)){ - dynamicallyGrantedPermissions.addAll(g.getPermissions()); + Collection<Permission> perms = g.getPermissions(); + Iterator<Permission> it = perms.iterator(); + while (it.hasNext()){ + pc.add(it.next()); + } } } if (thread.isInterrupted()) return false; -// if (loggable) { -// logger.log(Level.FINEST, "Grants: " + dynamicallyGrantedPermissions.toString()); -// } -// if (dynamicallyGrantedPermissions.isEmpty()) { -// // We have no dynamic grants -// return false; -// } - Iterator<Permission> dgpi = dynamicallyGrantedPermissions.iterator(); - while (dgpi.hasNext()){ - pc.add(dgpi.next()); - } - if (thread.isInterrupted()) return false; - // If we get refreshed the cache could be empty, which is more pedantic - // however the result may still be true so we'll return it anyway. -// if (loggable) { -// logger.log(Level.FINEST, "PermissionCollection: " + pc.toString()); -// } // We have added dynamic grants, lets expand any UmbrellaGrant's expandUmbrella(pc); - if ( pc.implies(permission) ){ - // The cache is replaced rather than updated, to avoid umbrella grants - // causing GrantPermission recursion. - if (domain != null ) cache.replace(domain, pc); - return true; + if (domain != null) { + if (transactionReadLock.tryLock()){ + try { + if (transactionID == currentTransactionID) + cache.putIfAbsent(domain, pc); + }finally { + transactionReadLock.unlock(); + } + } } - return false; + return pc.implies(permission); } /** @@ -630,9 +620,15 @@ Put the policy providers and all referen * */ + @SuppressWarnings("unchecked") public void refresh() { - cache.clear(); - basePolicy.refresh(); + transactionWriteLock.lock(); + try { + basePolicy.refresh(); + transactionID++; + }finally{ + transactionWriteLock.unlock(); + } // Clean up any void dynamic grants. Collection<PermissionGrant> remove = new ArrayList<PermissionGrant>(40); Iterator<PermissionGrant> i = dynamicPolicyGrants.iterator(); @@ -643,15 +639,24 @@ Put the policy providers and all referen } } dynamicPolicyGrants.removeAll(remove); + // Increment transaction ID after cache clear, + transactionWriteLock.lock(); + try { + cache.clear(); + transactionID++; + }finally{ + transactionWriteLock.unlock(); + } // Don't bother removing void from the remotePolicy, it get's replaced anyway. // Policy file based grant's don't become void, only dynamic grant's // to ProtectionDomain or ClassLoader. - SecurityManager sm = System.getSecurityManager(); + final SecurityManager sm = System.getSecurityManager(); if (sm != null){ if (sm instanceof DelegateSecurityManager){ ((DelegateSecurityManager) sm).clearFromCache(null); } } + } public boolean grantSupported() { @@ -684,10 +689,16 @@ Put the policy providers and all referen .permissions(permissions) .context(PermissionGrantBuilder.CLASSLOADER) .build(); - // We built this grant it's safe to trust. - grantCache.put(pe, permissions); // Replace any existing too. // This grant is new, in the grantCache and we trust it. dynamicPolicyGrants.add(pe); + // Increment transaction ID after cache clear, + transactionWriteLock.lock(); + try { + cache.clear(); + transactionID++; + }finally{ + transactionWriteLock.unlock(); + } // if (loggable){ // logger.log(Level.FINEST, "Granting: {0}", pe.toString()); // } @@ -745,8 +756,18 @@ Put the policy providers and all referen grants.remove(); } } - // Unfortunately this is quite expensive, but we don't know which ProtectionDomains a ClassLoader references. - cache.clear(); + // Unfortunately we don't know which + // ProtectionDomains a ClassLoader references, so we must clear the + // cache. + // Increment transaction ID after cache clear. + transactionWriteLock.lock(); + try { + cache.clear(); + transactionID++; + }finally{ + transactionWriteLock.unlock(); + } + SecurityManager sm = System.getSecurityManager(); if (sm instanceof DelegateSecurityManager) { ((DelegateSecurityManager) sm).clearFromCache(removed); @@ -832,7 +853,33 @@ Put the policy providers and all referen // changes between now and gaining the lock, only the length of the // HashSet is potentially not optimal, keeping the HashSet creation // outside of the lock reduces the lock held duration. - checkNullElements(grants); + Set<ProtectionDomain> domains = new HashSet<ProtectionDomain>(); + int l = grants.length; + for (int i = 0; i < l; i++ ){ + if (grants[i] == null ) throw new NullPointerException("null PermissionGrant prohibited"); + // This causes a ProtectionDomain security check. + final Class c = grants[i].getClass(); + List<ProtectionDomain> doms = AccessController.doPrivileged( + new PrivilegedAction<List<ProtectionDomain>>() { + public List<ProtectionDomain> run() { + Class[] classes = c.getDeclaredClasses(); + List<ProtectionDomain> domains = new ArrayList<ProtectionDomain>(); + int l = classes.length; + for ( int i = 0; i < l; i++ ){ + domains.add(classes[i].getProtectionDomain()); + } + return domains; + } + }); + domains.addAll(doms); + } + Iterator<ProtectionDomain> it = domains.iterator(); + while (it.hasNext()){ + if ( ! it.next().implies(implementsPermissionGrant)) { + throw new SecurityException("Missing permission: " + + implementsPermissionGrant.toString()); + } + } HashSet<PermissionGrant> holder = new HashSet<PermissionGrant>(grants.length); holder.addAll(Arrays.asList(grants)); @@ -843,7 +890,13 @@ Put the policy providers and all referen PermissionGrant[] updated = new PermissionGrant[holder.size()]; remotePolicyGrants = holder.toArray(updated); } - cache.clear(); + transactionWriteLock.lock(); + try { + cache.clear(); + transactionID++; + }finally{ + transactionWriteLock.unlock(); + } Collection<PermissionGrant> oldGrants = new HashSet<PermissionGrant>(old.length); oldGrants.addAll(Arrays.asList(old)); oldGrants.removeAll(holder); @@ -861,52 +914,5 @@ Put the policy providers and all referen } // oldGrants now only has the grants which have been removed. } - - /* - * The sole purpose of this implementation is to make Dynamic permissions - * printable for debugging from a ProtectionDomain without their contained - * permissions becoming merged in the static ProtectionDomain permissions. - */ - private static class PolicyPermission extends Permission { - private static final long serialVersionUID = 1L; - - private final Permission perm; - - PolicyPermission(Permission p){ - super("Dynamic Policy"); - perm = p; - } - - @Override - public boolean implies(Permission permission) { - return equals(permission); - } - - @Override - public boolean equals(Object obj) { - if (obj == this) return true; - if (obj instanceof PolicyPermission && - this.perm.equals(((PolicyPermission) obj).perm)) return true; - return false; - } - - @Override - public int hashCode() { - int hash = 7; - hash = 31 * hash + (this.perm != null ? this.perm.hashCode() : 0); - return hash; - } - - @Override - public String toString(){ - return perm.toString(); - } - - @Override - public String getActions() { - return ""; - } - - } }
Modified: river/jtsk/skunk/peterConcurrentPolicy/src/org/apache/river/api/security/DelegateCombinerSecurityManager.java URL: http://svn.apache.org/viewvc/river/jtsk/skunk/peterConcurrentPolicy/src/org/apache/river/api/security/DelegateCombinerSecurityManager.java?rev=1225993&r1=1225992&r2=1225993&view=diff ============================================================================== --- river/jtsk/skunk/peterConcurrentPolicy/src/org/apache/river/api/security/DelegateCombinerSecurityManager.java (original) +++ river/jtsk/skunk/peterConcurrentPolicy/src/org/apache/river/api/security/DelegateCombinerSecurityManager.java Sat Dec 31 00:13:00 2011 @@ -18,14 +18,15 @@ package org.apache.river.api.security; -import java.net.SocketPermission; import java.security.AccessControlContext; import java.security.AccessController; +import java.security.AllPermission; import java.security.DomainCombiner; import java.security.Guard; import java.security.Permission; import java.security.PrivilegedAction; import java.security.ProtectionDomain; +import java.security.SecurityPermission; import java.util.ArrayList; import java.util.Collection; import java.util.Comparator; @@ -40,11 +41,9 @@ import java.util.concurrent.ConcurrentMa import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; import java.util.concurrent.Future; import java.util.concurrent.SynchronousQueue; import java.util.concurrent.ThreadPoolExecutor; -import java.util.concurrent.ThreadPoolExecutor.CallerRunsPolicy; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import java.util.logging.Level; @@ -77,9 +76,13 @@ extends SecurityManager implements Deleg private final Action action; private final ExecutorService executor; private final Comparator<Referrer<Permission>> permCompare; + private final AccessControlContext SMContext; public DelegateCombinerSecurityManager(){ super(); + // Get context before this becomes a SecurityManager. + // super() checked the permission to create a SecurityManager. + SMContext = AccessController.getContext(); dc = new DelegateDomainCombiner(); ConcurrentMap<Referrer<AccessControlContext>, Referrer<AccessControlContext>> internal = @@ -90,7 +93,7 @@ extends SecurityManager implements Deleg = new ConcurrentHashMap<Referrer<AccessControlContext>, Referrer<Set<Permission>>>(100); checked = RC.concurrentMap(refmap, Ref.SOFT, Ref.STRONG); - g = new RevokePermission(); + g = new SecurityPermission("getPolicy"); action = new Action(); // Make this a tunable property. double blocking_coefficient = 0.6; // 0 CPU intensive to 0.9 IO intensive @@ -108,12 +111,19 @@ extends SecurityManager implements Deleg TimeUnit.SECONDS, new SynchronousQueue<Runnable>(), new ThreadPoolExecutor.CallerRunsPolicy()); permCompare = RC.comparator(new PermissionComparator()); + // Refresh the policy, in case it hasn't parsed all policy files. + java.security.Policy.getPolicy().refresh(); + } + + public void checkPermission(Permission perm) throws SecurityException { + checkPermission(perm, AccessController.getContext()); } @Override public void checkPermission(Permission perm, Object context) throws SecurityException { if (!(context instanceof AccessControlContext)) throw new SecurityException(); if (perm == null ) throw new NullPointerException("Permission Collection null"); + if (SMContext.equals(context)) return; // prevents endless loop in debug. AccessControlContext executionContext = (AccessControlContext) context; // Checks if Permission has already been checked for this context. Set<Permission> checkedPerms = checked.get(executionContext); @@ -125,43 +135,49 @@ extends SecurityManager implements Deleg if (existed != null) checkedPerms = existed; } if (checkedPerms.contains(perm)) return; // don't need to check again. - if (perm instanceof DelegatePermission) { - // This is an expensive operation, so we cache the created AccessControlContext. - AccessControlContext delegateContext = contextCache.get(executionContext); - if (delegateContext == null) { - final AccessControlContext finalExecutionContext = executionContext; - // Create a new AccessControlContext with the DelegateDomainCombiner - // we don't need to preserve the Subject accross the call - // we have sufficient privilege. - delegateContext = AccessController.doPrivileged( - new PrivilegedAction<AccessControlContext>(){ - public AccessControlContext run() { - return new AccessControlContext(finalExecutionContext, dc); - } + // This is an expensive operation, so we cache the created AccessControlContext. + AccessControlContext delegateContext = contextCache.get(executionContext); + if (delegateContext == null) { + final AccessControlContext finalExecutionContext = executionContext; + // Create a new AccessControlContext with the DelegateDomainCombiner + // we don't need to preserve the Subject accross the call + // we have sufficient privilege. + delegateContext = AccessController.doPrivileged( + new PrivilegedAction<AccessControlContext>(){ + public AccessControlContext run() { + return new AccessControlContext(finalExecutionContext, dc); } - ); - // Optimise the delegateContext, this runs the DelegateDomainCombiner - // and returns the AccessControlContext. - // This is a mutator method, the delegateContext returned - // is actually the same object passed in, after it is - // mutated, but just in case that changes in future we - // return it. - delegateContext = AccessController.doPrivileged(action, delegateContext); - contextCache.putIfAbsent(executionContext, delegateContext); - // Above putIfAbsent: It doesn't matter if it already existed, - // the context we have is valid to perform a permissionCheck. - } - executionContext = delegateContext; - } + } + ); + // Optimise the delegateContext, this runs the DelegateDomainCombiner + // and returns the AccessControlContext. + // This is a mutator method, the delegateContext returned + // is actually the same object passed in, after it is + // mutated, but just in case that changes in future we + // return it. + delegateContext = AccessController.doPrivileged(action, delegateContext); + contextCache.putIfAbsent(executionContext, delegateContext); + // Above putIfAbsent: It doesn't matter if it already existed, + // the context we have is valid to perform a permissionCheck. + } // Normal execution, same as SecurityManager. - executionContext.checkPermission(perm); + delegateContext.checkPermission(perm); /* It's ok to cache SocketPermission if we use a comparator */ // If we get to here, no exceptions were thrown, we have permission. // Don't cache SocketPermission. // if (perm instanceof SocketPermission) return; checkedPerms.add(perm); } - + + /** + * This method is intended to be called only by a Policy. + * + * To clear the cache of checked Permissions requires the following Permission: + * java.security.SecurityPermission("getPolicy"); + * + * @param perms + * @throws SecurityException + */ public void clearFromCache(Set<Permission> perms) throws SecurityException { // This is a slow operation, with the benefit // of faster security checks, which occur far more often. @@ -294,10 +310,11 @@ extends SecurityManager implements Deleg // interrupt status swallowed. boolean externalInterrupt = false; if (!terminated.get()) externalInterrupt = true; - - Iterator<Future<Boolean>> it = resultList.iterator(); - while (it.hasNext()){ - it.next().cancel(true); + if ( resultList != null ){ // could be interrupted before executor invoking. + Iterator<Future<Boolean>> it = resultList.iterator(); + while (it.hasNext()){ + it.next().cancel(true); + } } Logger.getLogger(DelegateCombinerSecurityManager.class.getName()).log(Level.FINEST, null, ex); // Task interruption is normal, it just means one task returned false. Copied: river/jtsk/skunk/peterConcurrentPolicy/src/org/apache/river/api/security/PolicyPermission.java (from r1222835, river/jtsk/skunk/peterConcurrentPolicy/src/org/apache/river/api/security/RevokePermission.java) URL: http://svn.apache.org/viewvc/river/jtsk/skunk/peterConcurrentPolicy/src/org/apache/river/api/security/PolicyPermission.java?p2=river/jtsk/skunk/peterConcurrentPolicy/src/org/apache/river/api/security/PolicyPermission.java&p1=river/jtsk/skunk/peterConcurrentPolicy/src/org/apache/river/api/security/RevokePermission.java&r1=1222835&r2=1225993&rev=1225993&view=diff ============================================================================== --- river/jtsk/skunk/peterConcurrentPolicy/src/org/apache/river/api/security/RevokePermission.java (original) +++ river/jtsk/skunk/peterConcurrentPolicy/src/org/apache/river/api/security/PolicyPermission.java Sat Dec 31 00:13:00 2011 @@ -5,49 +5,26 @@ package org.apache.river.api.security; -import java.security.Permission; +import java.security.BasicPermission; /** - * <p>RevokePermission allows for a permission to be revoked at runtime provided - * it has been dynamically granted.<p> - * - * A RevokePermission cannot dynamically grant itself a permission.<p> - * - * A domain with revoke permission can not revoke a RevokePermission - * unless it has been granted dynamically. </p> - * - * -- seems logical. + * <p>A "revoke" or "REVOKE" PolicyPermission is allows updating a + * RemotePolicy or remove Dynamically granted permission from a + * RevokeableDynamicPolicy.</p> * + * <p>A "implementPermissionGrant" PolicyPermission allows a class to implement + * org.apache.river.api.security.PermissionGrant interface and use it to + * update a RemotePolicy. This is not a permission to grant lightly, since + * a poor implementation could destabilise a policy or worse allow the caller + * to grant AllPermission anyone using mutation.</p> * * @author Peter Firmstone */ -public class RevokePermission extends Permission { +public class PolicyPermission extends BasicPermission { private static final long serialVersionUID = 1L; - public RevokePermission(){ - super(""); + public PolicyPermission(String name){ + super(name); } - @Override - public boolean implies(Permission permission) { - if ( !(permission instanceof RevokePermission)) return false; - if ( permission.getClass() != this.getClass()) return false; - return true; - } - - @Override - public boolean equals(Object obj) { - if (obj instanceof RevokePermission) return true; - return false; - } - - @Override - public int hashCode() { - return RevokePermission.class.hashCode(); - } - - @Override - public String getActions() { - return ""; - } } Modified: river/jtsk/skunk/peterConcurrentPolicy/src/org/apache/river/impl/security/policy/util/Messages.java URL: http://svn.apache.org/viewvc/river/jtsk/skunk/peterConcurrentPolicy/src/org/apache/river/impl/security/policy/util/Messages.java?rev=1225993&r1=1225992&r2=1225993&view=diff ============================================================================== --- river/jtsk/skunk/peterConcurrentPolicy/src/org/apache/river/impl/security/policy/util/Messages.java (original) +++ river/jtsk/skunk/peterConcurrentPolicy/src/org/apache/river/impl/security/policy/util/Messages.java Sat Dec 31 00:13:00 2011 @@ -242,7 +242,7 @@ public class Messages { // Attempt to load the messages. try { bundle = setLocale(Locale.getDefault(), - "org.apache.river.security.policy.util.messages"); //$NON-NLS-1$ + "org.apache.river.impl.security.policy.util.messages"); //$NON-NLS-1$ } catch (Throwable e) { e.printStackTrace(); } Modified: river/jtsk/skunk/peterConcurrentPolicy/src/org/apache/river/impl/util/AbstractReferenceComparator.java URL: http://svn.apache.org/viewvc/river/jtsk/skunk/peterConcurrentPolicy/src/org/apache/river/impl/util/AbstractReferenceComparator.java?rev=1225993&r1=1225992&r2=1225993&view=diff ============================================================================== --- river/jtsk/skunk/peterConcurrentPolicy/src/org/apache/river/impl/util/AbstractReferenceComparator.java (original) +++ river/jtsk/skunk/peterConcurrentPolicy/src/org/apache/river/impl/util/AbstractReferenceComparator.java Sat Dec 31 00:13:00 2011 @@ -31,8 +31,33 @@ abstract class AbstractReferenceComparat AbstractReferenceComparator() { } + /** + * This is implemented such that if either Referrer contains a null + * referent, the comparison is only made using Referrer's, this may + * have a different natural order, than the comparator provided, however + * equals will always return 0, this is important to correctly remove + * a Referrer once its referent has been collected. + * + * The following tests give this a good workout: + * + * com/sun/jini/test/impl/joinmanager/ZRegisterStorm.td + * com/sun/jini/test/spec/renewalmanager/EventTest.td + * + * @param o1 + * @param o2 + * @return + */ public int compare(Referrer<T> o1, Referrer<T> o2) { - return get().compare(o1 != null ? o1.get() : null, o2 != null ? o2.get() : null); + if (o1 == o2) return 0; + T t1 = o1.get(); + T t2 = o2.get(); + if ( t1 != null && t2 != null) return get().compare(t1, t2); + int hash1 = o1.hashCode(); + int hash2 = o2.hashCode(); + if (hash1 < hash2) return -1; + if (hash1 > hash2) return 1; + if (o1.equals(o2)) return 0; + return -1; } @Override Modified: river/jtsk/skunk/peterConcurrentPolicy/src/org/apache/river/impl/util/ReferenceFactory.java URL: http://svn.apache.org/viewvc/river/jtsk/skunk/peterConcurrentPolicy/src/org/apache/river/impl/util/ReferenceFactory.java?rev=1225993&r1=1225992&r2=1225993&view=diff ============================================================================== --- river/jtsk/skunk/peterConcurrentPolicy/src/org/apache/river/impl/util/ReferenceFactory.java (original) +++ river/jtsk/skunk/peterConcurrentPolicy/src/org/apache/river/impl/util/ReferenceFactory.java Sat Dec 31 00:13:00 2011 @@ -39,6 +39,7 @@ class ReferenceFactory<T> { private ReferenceFactory(){} static <T> Referrer<T> create(T t, ReferenceQueue<? super T> queue, Ref type ){ + if (t == null) throw new NullPointerException("Reference collections cannot contain null"); switch (type){ case WEAK_IDENTITY: return new ReferrerWrapper<T>(new WeakIdentityReferenceKey<T>(t, queue)); @@ -78,6 +79,7 @@ class ReferenceFactory<T> { * @return */ static <T> Referrer<T> singleUseForLookup(T t, Ref type){ + if (t == null) throw new NullPointerException("Reference collections cannot contain null"); switch (type){ case WEAK_IDENTITY: return new TempIdentityReferrer<T>(t);
