package org.eclipse.osgi.internal.permadmin;
import java.security.*;
import java.util.*;
import org.eclipse.osgi.internal.permadmin.SecurityRow.Decision;
import org.osgi.service.condpermadmin.Condition;
public class EquinoxSecurityManager extends SecurityManager {
static {
Class<?> c;
c = CheckPermissionAction.class;
c = CheckContext.class;
c.getName();
}
static class CheckContext {
List<List<Decision[]>> depthCondSets = new ArrayList<>(2);
List<AccessControlContext> accs = new ArrayList<>(2);
List<Class<?>> CondClassSet;
public int getDepth() {
return depthCondSets.size() - 1;
}
}
static class CheckPermissionAction implements PrivilegedAction<Void> {
Permission perm;
Object context;
EquinoxSecurityManager fsm;
CheckPermissionAction(EquinoxSecurityManager fsm, Permission perm, Object context) {
this.fsm = fsm;
this.perm = perm;
this.context = context;
}
@Override
public Void run() {
fsm.internalCheckPermission(perm, context);
return null;
}
}
private final ThreadLocal<CheckContext> localCheckContext = new ThreadLocal<>();
boolean addConditionsForDomain(Decision[] results) {
CheckContext cc = localCheckContext.get();
if (cc == null) {
return false;
}
List<Decision[]> condSets = cc.depthCondSets.get(cc.getDepth());
if (condSets == null) {
condSets = new ArrayList<>(1);
cc.depthCondSets.set(cc.getDepth(), condSets);
}
condSets.add(results);
return true;
}
boolean inCheckPermission() {
return localCheckContext.get() != null;
}
@Override
public void checkPermission(Permission perm, Object context) {
AccessController.doPrivileged(new CheckPermissionAction(this, perm, context));
}
public AccessControlContext getContextToBeChecked() {
CheckContext cc = localCheckContext.get();
if (cc != null && cc.accs != null && !cc.accs.isEmpty())
return cc.accs.get(cc.accs.size() - 1);
return null;
}
void internalCheckPermission(Permission perm, Object context) {
AccessControlContext acc = (AccessControlContext) context;
CheckContext cc = localCheckContext.get();
if (cc == null) {
cc = new CheckContext();
localCheckContext.set(cc);
}
cc.depthCondSets.add(null);
cc.accs.add(acc);
try {
acc.checkPermission(perm);
List<Decision[]> conditionSets = cc.depthCondSets.get(cc.getDepth());
if (conditionSets == null)
return;
Map<Class<? extends Condition>, Dictionary<Object, Object>> conditionDictionaries = new HashMap<>();
for (Decision[] domainDecisions : conditionSets) {
boolean grant = false;
for (Decision domainDecision : domainDecisions) {
if (domainDecision == null) {
break;
}
if ((domainDecision.decision & SecurityTable.ABSTAIN) != 0) {
continue;
}
if ((domainDecision.decision & SecurityTable.POSTPONED) == 0) {
if ((domainDecision.decision & SecurityTable.GRANTED) != 0) {
grant = true;
}
break;
}
int decision = getPostponedDecision(domainDecision, conditionDictionaries, cc);
if ((decision & SecurityTable.ABSTAIN) != 0)
continue;
if ((decision & SecurityTable.GRANTED) != 0)
grant = true;
break;
}
if (!grant)
throw new SecurityException("Conditions not satisfied");
}
} finally {
cc.depthCondSets.remove(cc.getDepth());
cc.accs.remove(cc.accs.size() - 1);
}
}
private int getPostponedDecision(Decision decision, Map<Class<? extends Condition>, Dictionary<Object, Object>> conditionDictionaries, CheckContext cc) {
Condition[] postponed = decision.postponed;
for (Condition postponedCond : postponed) {
Dictionary<Object, Object> condContext = conditionDictionaries.get(postponedCond.getClass());
if (condContext == null) {
condContext = new Hashtable<>();
conditionDictionaries.put(postponedCond.getClass(), condContext);
}
if (cc.CondClassSet == null)
cc.CondClassSet = new ArrayList<>(2);
if (cc.CondClassSet.contains(postponedCond.getClass())) {
return SecurityTable.ABSTAIN;
}
cc.CondClassSet.add(postponedCond.getClass());
try {
boolean mutable = postponedCond.isMutable();
boolean isSatisfied = postponedCond.isSatisfied(new Condition[]{postponedCond}, condContext);
decision.handleImmutable(postponedCond, isSatisfied, mutable);
if (!isSatisfied)
return SecurityTable.ABSTAIN;
} finally {
cc.CondClassSet.remove(postponedCond.getClass());
}
}
return decision.decision;
}
@Override
public void checkPermission(Permission perm) {
checkPermission(perm, getSecurityContext());
}
@Override
public Object getSecurityContext() {
return AccessController.getContext();
}
}