Return-Path: Delivered-To: apmail-incubator-river-commits-archive@minotaur.apache.org Received: (qmail 781 invoked from network); 1 Apr 2010 21:13:42 -0000 Received: from unknown (HELO mail.apache.org) (140.211.11.3) by 140.211.11.9 with SMTP; 1 Apr 2010 21:13:42 -0000 Received: (qmail 40931 invoked by uid 500); 1 Apr 2010 21:13:42 -0000 Delivered-To: apmail-incubator-river-commits-archive@incubator.apache.org Received: (qmail 40874 invoked by uid 500); 1 Apr 2010 21:13:41 -0000 Mailing-List: contact river-commits-help@incubator.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: river-dev@incubator.apache.org Delivered-To: mailing list river-commits@incubator.apache.org Received: (qmail 40867 invoked by uid 99); 1 Apr 2010 21:13:41 -0000 Received: from nike.apache.org (HELO nike.apache.org) (192.87.106.230) by apache.org (qpsmtpd/0.29) with ESMTP; Thu, 01 Apr 2010 21:13:41 +0000 X-ASF-Spam-Status: No, hits=-2000.0 required=10.0 tests=ALL_TRUSTED X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Thu, 01 Apr 2010 21:13:37 +0000 Received: by eris.apache.org (Postfix, from userid 65534) id 8DB8623888DD; Thu, 1 Apr 2010 21:13:16 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r930099 - /incubator/river/jtsk/trunk/src/org/apache/river/security/concurrent/DyanamicConcurrentPolicyProvider.java Date: Thu, 01 Apr 2010 21:13:16 -0000 To: river-commits@incubator.apache.org From: peter_firmstone@apache.org X-Mailer: svnmailer-1.0.8 Message-Id: <20100401211316.8DB8623888DD@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org Author: peter_firmstone Date: Thu Apr 1 21:13:16 2010 New Revision: 930099 URL: http://svn.apache.org/viewvc?rev=930099&view=rev Log: DynamicConcurrentPolicyProvider refactor java 1.5 dependant, unit test to follow. Modified: incubator/river/jtsk/trunk/src/org/apache/river/security/concurrent/DyanamicConcurrentPolicyProvider.java Modified: incubator/river/jtsk/trunk/src/org/apache/river/security/concurrent/DyanamicConcurrentPolicyProvider.java URL: http://svn.apache.org/viewvc/incubator/river/jtsk/trunk/src/org/apache/river/security/concurrent/DyanamicConcurrentPolicyProvider.java?rev=930099&r1=930098&r2=930099&view=diff ============================================================================== --- incubator/river/jtsk/trunk/src/org/apache/river/security/concurrent/DyanamicConcurrentPolicyProvider.java (original) +++ incubator/river/jtsk/trunk/src/org/apache/river/security/concurrent/DyanamicConcurrentPolicyProvider.java Thu Apr 1 21:13:16 2010 @@ -2,15 +2,19 @@ package org.apache.river.security.concurrent; +import java.security.AccessController; +import java.security.AllPermission; import java.security.CodeSource; import java.security.Permission; import java.security.PermissionCollection; import java.security.Policy; import java.security.Principal; +import java.security.PrivilegedAction; import java.security.ProtectionDomain; import java.security.Provider; import java.util.Arrays; import java.util.Collection; +import java.util.Collections; import java.util.HashSet; import java.util.Iterator; import java.util.Set; @@ -18,6 +22,7 @@ import java.util.concurrent.ConcurrentMa import java.util.concurrent.locks.ReentrantReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock; import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock; +import net.jini.security.GrantPermission; import net.jini.security.policy.DynamicPolicy; import net.jini.security.policy.PolicyInitializationException; import org.apache.river.security.policy.spi.RevokeableDynamicPolicySpi; @@ -26,42 +31,42 @@ import org.apache.river.security.policy. import org.apache.river.util.concurrent.WeakIdentityMap; /** - * This is a Dynamic Policy Provider that supports concurrent access, + *

This is a Dynamic Policy Provider that supports concurrent access, * for instances where a Policy provider is used for a distributed network * of computers, or where there is a large number of ProtectionDomains and * hence the opportunity for concurrency exists, concurrency comes with a - * cost however, that of increased memory usage. + * cost however, that of increased memory usage.

* - * Due to the Java 2 Security system's static design, a Policy Provider + *

Due to the Java 2 Security system's static design, a Policy Provider * can only augment the policy files utilised, that is it can only relax security * by granting additional permissions, this implementation adds an experimental - * feature for revoking permissions, however there are some caveats: + * feature for revoking permissions, however there are some caveats:

* - * Firstly if the Policy.refresh() method is called, followed by the + *

Firstly if the Policy.refresh() method is called, followed by the * ProtectionDomain.toString() method, the ProtectionDomain * merge the permissions, from the policy with those in the ProtectionDomain, * a ProtectionDomain cannot have Permissions - * removed, only additional merged. + * removed, only additional merged.

* - * So in order to prevent dynamic grants from finding + *

So in order to prevent dynamic grants from finding * their way into a ProtectionDomain's private PermissionCollection, * one would have to ensure that no dynamically grantable permissions are - * returned via the methods: - * + * returned via the methods:

+ *

* getPermissions(Codesource source) or * getPermissions(ProtectionDomain domain) - * - * This is different to the behaviour of the existing Jini 2.0 + *

+ *

This is different to the behaviour of the existing Jini 2.0 * DynamicPolicyProvider implementation where dynamically granted Permissions * are added. * * However when a Policy is checked via implies(ProtectionDomain d, Permission p) - * this implementation checks the dynamic grants. + * this implementation checks the dynamic grants * * This means that if a DynamicPolicy is utilised as the base Policy class * and if it returns dynamically granted permissions, then those permissions - * cannot be revoked. - * + * cannot be revoked.

+ *

* It is thus reccommeded that Static policy files only be used for files * where the level of trust is relatively static. This is the only implementation * where a dyanamic grant can be removed. In the case of Proxy trust, a proxy @@ -70,19 +75,19 @@ import org.apache.river.util.concurrent. * cannot be given a thread of control to find it's server because it has * already attained too many Permissions. In this new implementation it should * be possible to revoke AllPermission and grant Permissions dynamically as - * trust is gained. - * + * trust is gained.

+ *

* This may cause some undesireable side effects in existing programs. - * + *

* There is one final reccommendation and that is adopting / utilising an OSGi * Framework to enable far greater control over dynamic Permissions than this hack * implementation provides. - * + *

* To make the best utilisation of this Policy provider, set the System property: - * + *

,

* net.jini.security.policy.PolicyFileProvider.basePolicyClass = * org.apache.river.security.concurrent.ConcurrentPolicyFile - * + *

* @author Peter Firmstone * @version 1 * @since 2.2 @@ -94,6 +99,10 @@ import org.apache.river.util.concurrent. */ public class DyanamicConcurrentPolicyProvider implements RevokeableDynamicPolicySpi { + private static final ProtectionDomain sysDomain = + AccessController.doPrivileged(new PrivilegedAction() { + public ProtectionDomain run() { return Object.class.getProtectionDomain(); } + }); // A set of PolicyEntries constituting this Policy. // PolicyEntry is lighter weight than PermissionCollection. @@ -132,7 +141,8 @@ public class DyanamicConcurrentPolicyPro /** * Idempotent method. - */ + * @throws net.jini.security.policy.PolicyInitializationException + */ public void initialize() throws PolicyInitializationException { if (basePolicy == null) throw new PolicyInitializationException("Base Policy hasn't " + "been set cannot initialize", new Exception("Failed to initialize")); @@ -140,9 +150,16 @@ public class DyanamicConcurrentPolicyPro initialized = true; } + /** + * Ensures that any classes depended on by this policy provider are + * resolved. This is to preclude lazy resolution of such classes during + * operation of the provider, which can result in deadlock as described by + * bug 4911907. + */ public void ensureDependenciesResolved() { if (initialized == false) throw new RuntimeException("Object not initialized"); - + // Investigate bug 4911907, do we need to do anything more here? Is this sufficient. + implies(sysDomain, new AllPermission()); } public void revoke(Class cl, Principal[] principals, Permission[] permissions) { @@ -203,12 +220,12 @@ public class DyanamicConcurrentPolicyPro public PermissionCollection getPermissions(CodeSource codesource) { if (initialized == false) throw new RuntimeException("Object not initialized"); - throw new UnsupportedOperationException("Not supported yet."); + return basePolicy.getPermissions(codesource); } public PermissionCollection getPermissions(ProtectionDomain domain) { if (initialized == false) throw new RuntimeException("Object not initialized"); - throw new UnsupportedOperationException("Not supported yet."); + return basePolicy.getPermissions(domain); } public boolean implies(ProtectionDomain domain, Permission permission) { @@ -218,19 +235,10 @@ public class DyanamicConcurrentPolicyPro // Then check the base policy if (basePolicy.implies(domain, permission)) return true; // If it doesn't then we should check if it has any grants - Collection dynamicallyGrantedPermissions = null; - try { - rl.lock(); - Iterator it = dynamicGrants.iterator(); - while (it.hasNext()) { - PolicyEntry ge = it.next(); - if (ge.impliesPrincipals(domain == null ? null : domain.getPrincipals()) - && ge.impliesCodeSource(domain == null ? null : domain.getCodeSource())) { - dynamicallyGrantedPermissions = ge.getPermissions(); - } - } - } finally { rl.unlock(); } - if (dynamicallyGrantedPermissions == null) return false; + CodeSource cs = (domain == null ? null : domain.getCodeSource()); + Principal[] pals = (domain == null ? null : domain.getPrincipals()); + Collection dynamicallyGrantedPermissions = getGrants(cs, pals); + //if (dynamicallyGrantedPermissions == null) return false; //Is the null reference check performance worth it? if (dynamicallyGrantedPermissions.isEmpty()) return false; // Operation starts to get expensive PermissionCollection pc = null; @@ -266,7 +274,20 @@ public class DyanamicConcurrentPolicyPro } public void grant(Class cl, Principal[] principals, Permission[] permissions) { - CodeSource cs = cl.getProtectionDomain().getCodeSource(); + CodeSource cs = getDomain(cl).getCodeSource(); + if (principals != null && principals.length > 0) { + principals = principals.clone(); + checkNullElements(principals); + } + if (permissions == null || permissions.length == 0) { + return; + } + permissions = permissions.clone(); + checkNullElements(permissions); + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + sm.checkPermission(new GrantPermission(permissions)); + } Collection pal = Arrays.asList(principals); Collection perm = Arrays.asList(permissions); PolicyEntry pe = new PolicyEntry(cs, pal, perm); @@ -275,9 +296,56 @@ public class DyanamicConcurrentPolicyPro dynamicGrants.add(pe); } finally {wl.unlock();} } - + + // documentation inherited from DynamicPolicy.getGrants public Permission[] getGrants(Class cl, Principal[] principals) { - throw new UnsupportedOperationException("Not supported yet."); + if (initialized == false) throw new RuntimeException("Object not initialized"); + CodeSource cs = null; + if ( cl != null ) {cs = getDomain(cl).getCodeSource();} + // defensive copy array + if (principals != null && principals.length > 0) { + principals = principals.clone(); + checkNullElements(principals); + } + Collection cperms = getGrants(cs, principals); + Permission[] perms = cperms.toArray(new Permission[cperms.size()]); + return perms; } + + private Collection getGrants(CodeSource cs, Principal[] principals ){ + Collection dynamicallyGrantedPermissions = Collections.emptySet(); + try { + rl.lock(); + Iterator it = dynamicGrants.iterator(); + while (it.hasNext()) { + PolicyEntry ge = it.next(); + if (ge.impliesPrincipals(principals) + && ge.impliesCodeSource(cs)) { + dynamicallyGrantedPermissions = ge.getPermissions(); + } + } + } finally { rl.unlock(); } + return dynamicallyGrantedPermissions; + } + + private static void checkNullElements(Object[] array) { + for (int i = 0; i < array.length; i++) { + if (array[i] == null) { + throw new NullPointerException(); + } + } + } + + private static ProtectionDomain getDomain(final Class cl) { + ProtectionDomain pd = AccessController.doPrivileged( + new PrivilegedAction() { + public ProtectionDomain run() { return cl.getProtectionDomain(); } + }); + if (pd != sysDomain && pd.getClassLoader() == null) { + throw new UnsupportedOperationException( + "ungrantable protection domain"); + } + return pd; + } }