[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
Re: [equinox-dev] principal based permissions in osgi

Here is a patch to FrameworkSecurityManager and an implementation of 
PrincipalCondition. Subject.doAsXXX() methods function as normal. Principal 
to Permission bindings are done through ConditionalPermissionAdmin. For 
example, a ConditionalPermissionInfo of the form:

[...BundleLocationCondition http://www.ibm.com/-]
[...PrincipalCondition SuperMan]
(java.security.AllPermission)

says that when classes from a bundle from www.ibm.com are run with SuperMan 
set as the current Subject, they will have AllPermission.

Initial tests (thanx Pascal) indicate that it's working.

One thing (of many) to remember when playing with JAAS is that 
Subject.doAsXXX() is a glorified AccessController.doPrivileged(). The biggest 
outcome is that a Subject (and it's principals) get associated with a new  
AccessControlContext. A subtle effect of this is that if a doPrivileged is 
done inside of a doAsXXX() the new AccessControlContext setup by the 
doPrivileged will lose the Subject.

The current AccessControlContext (ACC) can be extracted using 
SecurityManager.getSecurityContext(), passed around, and evaluated directly 
using SecurityManager.checkPermission(Permission, Object). It is for this 
reason that PrincipalCondition needs to get a reference to the ACC being 
checked, since it may not be the same as the one returned from 
AccessController.getContext().

The attached patch adds a method for the PrincipalCondition to get the ACC 
being evaluated so that we can get the Subject of correct ACC. Because 
PrincipalCondition depends on a SecurityManager that has the added methods, 
the implementation of PrincipalCondition is not portable (it cannot be run on 
other OSGi implementations). It would be nice to standardize a way for 
Conditions to get the ACC being evaluated. If in the future DomainCombiners 
are used in other ways, corresponding conditions would also need the ACC.

ben

On Thursday 15 September 2005 12:00 pm, Pascal Rapicault wrote:
> Hi,
>
> Lately I've been looking at JAAS and its capability to dynamically
> associate permissions based on principals (usually declared in a policy
> file) and from that to use Subject.doAsPriviledged.
> Given that OSGi has its own way of expressing permissions, I would like to
> understand how principal based permissions can be declared.
>
> Thank you,
>
> PaScaL
Index: FrameworkSecurityManager.java
===================================================================
RCS file: /home/eclipse/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/FrameworkSecurityManager.java,v
retrieving revision 1.3
diff -u -r1.3 FrameworkSecurityManager.java
--- FrameworkSecurityManager.java	28 Jul 2005 14:53:36 -0000	1.3
+++ FrameworkSecurityManager.java	16 Sep 2005 18:51:48 -0000
@@ -35,6 +35,7 @@
 	static class CheckContext {
 		// A non zero depth indicates that we are doing a recursive permission check.
 		ArrayList depthCondSets = new ArrayList(2);
+        ArrayList accs = new ArrayList(2);
 		ArrayList CondClassSet;
 
 		public int getDepth() {
@@ -88,6 +89,23 @@
 		AccessController.doPrivileged(new CheckPermissionAction(this, perm, context));
 	}
 
+	/**
+     * Gets the AccessControlContext currently being evaluated by
+     * the SecurityManager.
+     * 
+	 * @return the AccessControlContext currently being evaluated by the SecurityManager, or
+     * null if no AccessControlContext is being evaluted. Note: this method will
+     * return null if the permission check is being done directly on the AccessControlContext
+     * rather than the SecurityManager.
+	 */
+	public AccessControlContext getContextToBeChecked() {
+        CheckContext cc = (CheckContext) localCheckContext.get();
+        if (cc != null && cc.accs != null && !cc.accs.isEmpty()) {
+            return (AccessControlContext) cc.accs.get(cc.accs.size()-1);
+        }
+        return null;
+    }
+    
 	public void internalCheckPermission(Permission perm, Object context) {
 		AccessControlContext acc = (AccessControlContext) context;
 		CheckContext cc = (CheckContext) localCheckContext.get();
@@ -96,6 +114,7 @@
 			localCheckContext.set(cc);
 		}
 		cc.depthCondSets.add(null); // initialize postponed condition set to null
+        cc.accs.add(acc);
 		try {
 			acc.checkPermission(perm);
 			// We want to pop the first set of postponed conditions and process them
@@ -121,6 +140,7 @@
 			}
 		} finally {
 			cc.depthCondSets.remove(cc.getDepth());
+            cc.accs.remove(cc.accs.size()-1);
 		}
 	}
 
/* Created on Sep 15, 2005
 * Copyright 2005 IBM Corp
 * Use the Source Duke!
 * Brought to you by breed and the letter Q. */
package org.eclipse.experimental.condition;

import java.security.AccessControlContext;
import java.security.Principal;
import java.util.Dictionary;
import java.util.Iterator;
import java.util.Set;
import java.util.WeakHashMap;
import javax.security.auth.Subject;
import org.eclipse.osgi.framework.internal.core.FrameworkSecurityManager;
import org.osgi.framework.Bundle;
import org.osgi.service.condpermadmin.Condition;
import org.osgi.service.condpermadmin.ConditionInfo;
/**
 * This is a mutable, but not postponed, Condition that checks
 * the current Subject against a specified Principal. The
 * Condition will always take one argument: the name of the 
 * Principal. The condition is satisfied if the Subject of
 * the AccessControlContext being evaluated has a Principal
 * whose name matches the specified name.
 * <p>
 * In order to find the Subject of the AccessControlContext
 * the PricipalCondition, must have a reference to the ACC
 * being evaluated. Unfortunately, Java does not have a way
 * of getting the ACC, so we rely on a special SecurityManager
 * to give it to us.
 * <p>
 * We definate a getInstance method and a WeakHashMap to keep
 * the number of instances of Conditions to a minimum.
 * </p>
 * The ConditionalInfo for this condition will have the form:
 * <pre>
 * [org.eclipse.experimental.condition.PrincipleCondition "name-of-principal"]
 * </pre>
 *
 * @author Benjamin Reed (breed@xxxxxxxxxxxxxxx)
 */
public class PrincipalCondition implements Condition {
    String principal;
    public static Condition getInstance(Bundle b, ConditionInfo ci) {
        if (ci.getArgs() != null && ci.getArgs().length == 1) {
            return getConditionForName(ci.getArgs()[0]);
        }
        return Condition.FALSE;
    }
    private static WeakHashMap nameCond = new WeakHashMap(4);
    private static Condition getConditionForName(String name) {
        Condition cond = (Condition) nameCond.get(name);
        if (cond == null) {
            cond = new PrincipalCondition(name);
            nameCond.put(name, cond);
        }
        return cond;
    }
    PrincipalCondition(String name) {
        this.principal = name;
    }
    public boolean isPostponed() {
        return false;
    }
    public boolean isSatisfied() {
        Subject subject = null;
        /* If the hook is not installed we return false */
        SecurityManager sm = System.getSecurityManager();
        if (sm == null || !(sm instanceof FrameworkSecurityManager)) {
            return false;
        }
        
        AccessControlContext acc = ((FrameworkSecurityManager)sm).getContextToBeChecked();
        subject = Subject.getSubject(acc);
        if (subject == null) return false;
        
        Set principals = subject.getPrincipals();
        if (principals == null || principals.isEmpty()) return false;
        for(Iterator i = principals.iterator(); i.hasNext();) {
            Principal p = (Principal) i.next();
            if (p.getName().equals(this.principal)) {
                return true;
            }
        }
        return false;
    }
    public boolean isMutable() {
        return true;
    }
    public boolean isSatisfied(Condition[] arg0, Dictionary arg1) {
        // This will not be called since we aren't Postponed
        return false;
    }
}