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