You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@river.apache.org by pe...@apache.org on 2010/04/01 23:13:16 UTC
svn commit: r930099 -
/incubator/river/jtsk/trunk/src/org/apache/river/security/concurrent/DyanamicConcurrentPolicyProvider.java
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,
+ * <p>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.</p>
*
- * Due to the Java 2 Security system's static design, a Policy Provider
+ * <p>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:</p>
*
- * Firstly if the Policy.refresh() method is called, followed by the
+ * <p>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. </p>
*
- * So in order to prevent dynamic grants from finding
+ * <p>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:</p>
+ * <p>
* getPermissions(Codesource source) or
* getPermissions(ProtectionDomain domain)
- *
- * This is different to the behaviour of the existing Jini 2.0
+ * </p>
+ * <p>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.</p>
+ * <p>
* 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.</p>
+ * <p>
* This may cause some undesireable side effects in existing programs.
- *
+ * </p><p>
* 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.
- *
+ * </p><p>
* To make the best utilisation of this Policy provider, set the System property:
- *
+ * </p>,<p>
* net.jini.security.policy.PolicyFileProvider.basePolicyClass =
* org.apache.river.security.concurrent.ConcurrentPolicyFile
- *
+ * </p>
* @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<ProtectionDomain>() {
+ 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<Permission> dynamicallyGrantedPermissions = null;
- try {
- rl.lock();
- Iterator<PolicyEntry> 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<Permission> 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<Principal> pal = Arrays.asList(principals);
Collection<Permission> 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<Permission> cperms = getGrants(cs, principals);
+ Permission[] perms = cperms.toArray(new Permission[cperms.size()]);
+ return perms;
}
+
+ private Collection<Permission> getGrants(CodeSource cs, Principal[] principals ){
+ Collection<Permission> dynamicallyGrantedPermissions = Collections.emptySet();
+ try {
+ rl.lock();
+ Iterator<PolicyEntry> 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<ProtectionDomain>() {
+ public ProtectionDomain run() { return cl.getProtectionDomain(); }
+ });
+ if (pd != sysDomain && pd.getClassLoader() == null) {
+ throw new UnsupportedOperationException(
+ "ungrantable protection domain");
+ }
+ return pd;
+ }
}