blob: 62d41267458321009053ac52a4e7ddbaa322595f [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2008, 2009 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.osgi.internal.permadmin;
import java.security.Permission;
import java.security.PermissionCollection;
import java.util.Enumeration;
import org.eclipse.osgi.internal.permadmin.SecurityRow.Decision;
public class SecurityTable extends PermissionCollection {
private static final long serialVersionUID = -1800193310096318060L;
static final int GRANTED = 0x0001;
static final int DENIED = 0x0002;
static final int ABSTAIN = 0x0004;
static final int POSTPONED = 0x0008;
private final SecurityRow[] rows;
private final SecurityAdmin securityAdmin;
public SecurityTable(SecurityAdmin securityAdmin, SecurityRow[] rows) {
if (rows == null)
throw new NullPointerException("rows cannot be null!!"); //$NON-NLS-1$
this.rows = rows;
this.securityAdmin = securityAdmin;
}
boolean isEmpty() {
return rows.length == 0;
}
int evaluate(BundlePermissions bundlePermissions, Permission permission) {
if (isEmpty())
return ABSTAIN;
boolean postponed = false;
Decision[] results = new Decision[rows.length];
int immediateDecisionIdx = -1;
// evaluate each row
for (int i = 0; i < rows.length; i++) {
try {
results[i] = rows[i].evaluate(bundlePermissions, permission);
} catch (Throwable t) {
// TODO log?
results[i] = SecurityRow.DECISION_ABSTAIN;
}
if ((results[i].decision & ABSTAIN) != 0)
continue; // ignore this row and continue to next row
if ((results[i].decision & POSTPONED) != 0) {
// row is postponed; we can no longer return quickly on a denied decision
postponed = true;
continue; // continue to next row
}
if (!postponed)
// no postpones encountered yet; we can return the decision quickly
return results[i].decision; // return GRANTED or DENIED
// got an immediate answer; but it is after a postponed condition.
// no need to process the rest of the rows
immediateDecisionIdx = i;
break;
}
if (postponed) {
int immediateDecision = immediateDecisionIdx < 0 ? DENIED : results[immediateDecisionIdx].decision;
// iterate over all postponed conditions;
// if they all provide the same decision as the immediate decision then return the immediate decision
boolean allSameDecision = true;
int i = immediateDecisionIdx < 0 ? results.length - 1 : immediateDecisionIdx - 1;
for (; i >= 0 && allSameDecision; i--) {
if (results[i] == null)
continue;
if ((results[i].decision & POSTPONED) != 0) {
if ((results[i].decision & immediateDecision) == 0)
allSameDecision = false;
else
results[i] = SecurityRow.DECISION_ABSTAIN; // we can clear postpones with the same decision as the immediate
}
}
if (allSameDecision)
return immediateDecision;
// we now are forced to postpone; we need to also remember the postponed decisions and
// the immediate decision if there is one.
EquinoxSecurityManager equinoxManager = securityAdmin.getSupportedSecurityManager();
if (equinoxManager == null)
// TODO this is really an error condition.
// This should never happen. We checked for a supported manager when the row was postponed
return ABSTAIN;
equinoxManager.addConditionsForDomain(results);
}
return postponed ? POSTPONED : ABSTAIN;
}
SecurityRow getRow(int i) {
return rows.length <= i || i < 0 ? null : rows[i];
}
SecurityRow getRow(String name) {
for (int i = 0; i < rows.length; i++) {
if (name.equals(rows[i].getName()))
return rows[i];
}
return null;
}
SecurityRow[] getRows() {
return rows;
}
String[] getEncodedRows() {
String[] encoded = new String[rows.length];
for (int i = 0; i < rows.length; i++)
encoded[i] = rows[i].getEncoded();
return encoded;
}
public void add(Permission permission) {
throw new SecurityException();
}
public Enumeration elements() {
return BundlePermissions.EMPTY_ENUMERATION;
}
public boolean implies(Permission permission) {
return (evaluate(null, permission) & SecurityTable.GRANTED) != 0;
}
}