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;
+    }  
 
 }