8014097: add doPrivileged methods with limited privilege scope
Reviewed-by: mchung
This commit is contained in:
parent
6ffe8293b9
commit
c0c2397857
@ -85,6 +85,15 @@ public final class AccessControlContext {
|
|||||||
|
|
||||||
private DomainCombiner combiner = null;
|
private DomainCombiner combiner = null;
|
||||||
|
|
||||||
|
// limited privilege scope
|
||||||
|
private Permission permissions[];
|
||||||
|
private AccessControlContext parent;
|
||||||
|
private boolean isWrapped;
|
||||||
|
|
||||||
|
// is constrained by limited privilege scope?
|
||||||
|
private boolean isLimited;
|
||||||
|
private ProtectionDomain limitedContext[];
|
||||||
|
|
||||||
private static boolean debugInit = false;
|
private static boolean debugInit = false;
|
||||||
private static Debug debug = null;
|
private static Debug debug = null;
|
||||||
|
|
||||||
@ -178,14 +187,79 @@ public final class AccessControlContext {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* package private for AccessController
|
* package private for AccessController
|
||||||
|
*
|
||||||
|
* This "argument wrapper" context will be passed as the actual context
|
||||||
|
* parameter on an internal doPrivileged() call used in the implementation.
|
||||||
*/
|
*/
|
||||||
AccessControlContext(ProtectionDomain context[], DomainCombiner combiner) {
|
AccessControlContext(ProtectionDomain caller, DomainCombiner combiner,
|
||||||
|
AccessControlContext parent, AccessControlContext context,
|
||||||
|
Permission[] perms)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Combine the domains from the doPrivileged() context into our
|
||||||
|
* wrapper context, if necessary.
|
||||||
|
*/
|
||||||
|
ProtectionDomain[] callerPDs = null;
|
||||||
|
if (caller != null) {
|
||||||
|
callerPDs = new ProtectionDomain[] { caller };
|
||||||
|
}
|
||||||
if (context != null) {
|
if (context != null) {
|
||||||
this.context = context.clone();
|
if (combiner != null) {
|
||||||
|
this.context = combiner.combine(callerPDs, context.context);
|
||||||
|
} else {
|
||||||
|
this.context = combine(callerPDs, context.context);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
* Call combiner even if there is seemingly nothing to combine.
|
||||||
|
*/
|
||||||
|
if (combiner != null) {
|
||||||
|
this.context = combiner.combine(callerPDs, null);
|
||||||
|
} else {
|
||||||
|
this.context = combine(callerPDs, null);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
this.combiner = combiner;
|
this.combiner = combiner;
|
||||||
|
|
||||||
|
Permission[] tmp = null;
|
||||||
|
if (perms != null) {
|
||||||
|
tmp = new Permission[perms.length];
|
||||||
|
for (int i=0; i < perms.length; i++) {
|
||||||
|
if (perms[i] == null) {
|
||||||
|
throw new NullPointerException("permission can't be null");
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* An AllPermission argument is equivalent to calling
|
||||||
|
* doPrivileged() without any limit permissions.
|
||||||
|
*/
|
||||||
|
if (perms[i].getClass() == AllPermission.class) {
|
||||||
|
parent = null;
|
||||||
|
}
|
||||||
|
tmp[i] = perms[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* For a doPrivileged() with limited privilege scope, initialize
|
||||||
|
* the relevant fields.
|
||||||
|
*
|
||||||
|
* The limitedContext field contains the union of all domains which
|
||||||
|
* are enclosed by this limited privilege scope. In other words,
|
||||||
|
* it contains all of the domains which could potentially be checked
|
||||||
|
* if none of the limiting permissions implied a requested permission.
|
||||||
|
*/
|
||||||
|
if (parent != null) {
|
||||||
|
this.limitedContext = combine(parent.context, parent.limitedContext);
|
||||||
|
this.isLimited = true;
|
||||||
|
this.isWrapped = true;
|
||||||
|
this.permissions = tmp;
|
||||||
|
this.parent = parent;
|
||||||
|
this.privilegedContext = context; // used in checkPermission2()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* package private constructor for AccessController.getContext()
|
* package private constructor for AccessController.getContext()
|
||||||
*/
|
*/
|
||||||
@ -260,6 +334,13 @@ public final class AccessControlContext {
|
|||||||
if (sm != null) {
|
if (sm != null) {
|
||||||
sm.checkPermission(SecurityConstants.GET_COMBINER_PERMISSION);
|
sm.checkPermission(SecurityConstants.GET_COMBINER_PERMISSION);
|
||||||
}
|
}
|
||||||
|
return getCombiner();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* package private for AccessController
|
||||||
|
*/
|
||||||
|
DomainCombiner getCombiner() {
|
||||||
return combiner;
|
return combiner;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -335,8 +416,10 @@ public final class AccessControlContext {
|
|||||||
or the first domain was a Privileged system domain. This
|
or the first domain was a Privileged system domain. This
|
||||||
is to make the common case for system code very fast */
|
is to make the common case for system code very fast */
|
||||||
|
|
||||||
if (context == null)
|
if (context == null) {
|
||||||
|
checkPermission2(perm);
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
for (int i=0; i< context.length; i++) {
|
for (int i=0; i< context.length; i++) {
|
||||||
if (context[i] != null && !context[i].implies(perm)) {
|
if (context[i] != null && !context[i].implies(perm)) {
|
||||||
@ -370,20 +453,108 @@ public final class AccessControlContext {
|
|||||||
debug.println("access allowed "+perm);
|
debug.println("access allowed "+perm);
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
checkPermission2(perm);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check the domains associated with the limited privilege scope.
|
||||||
|
*/
|
||||||
|
private void checkPermission2(Permission perm) {
|
||||||
|
if (!isLimited) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check the doPrivileged() context parameter, if present.
|
||||||
|
*/
|
||||||
|
if (privilegedContext != null) {
|
||||||
|
privilegedContext.checkPermission2(perm);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Ignore the limited permissions and parent fields of a wrapper
|
||||||
|
* context since they were already carried down into the unwrapped
|
||||||
|
* context.
|
||||||
|
*/
|
||||||
|
if (isWrapped) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Try to match any limited privilege scope.
|
||||||
|
*/
|
||||||
|
if (permissions != null) {
|
||||||
|
Class<?> permClass = perm.getClass();
|
||||||
|
for (int i=0; i < permissions.length; i++) {
|
||||||
|
Permission limit = permissions[i];
|
||||||
|
if (limit.getClass().equals(permClass) && limit.implies(perm)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check the limited privilege scope up the call stack or the inherited
|
||||||
|
* parent thread call stack of this ACC.
|
||||||
|
*/
|
||||||
|
if (parent != null) {
|
||||||
|
/*
|
||||||
|
* As an optimization, if the parent context is the inherited call
|
||||||
|
* stack context from a parent thread then checking the protection
|
||||||
|
* domains of the parent context is redundant since they have
|
||||||
|
* already been merged into the child thread's context by
|
||||||
|
* optimize(). When parent is set to an inherited context this
|
||||||
|
* context was not directly created by a limited scope
|
||||||
|
* doPrivileged() and it does not have its own limited permissions.
|
||||||
|
*/
|
||||||
|
if (permissions == null) {
|
||||||
|
parent.checkPermission2(perm);
|
||||||
|
} else {
|
||||||
|
parent.checkPermission(perm);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Take the stack-based context (this) and combine it with the
|
* Take the stack-based context (this) and combine it with the
|
||||||
* privileged or inherited context, if need be.
|
* privileged or inherited context, if need be. Any limited
|
||||||
|
* privilege scope is flagged regardless of whether the assigned
|
||||||
|
* context comes from an immediately enclosing limited doPrivileged().
|
||||||
|
* The limited privilege scope can indirectly flow from the inherited
|
||||||
|
* parent thread or an assigned context previously captured by getContext().
|
||||||
*/
|
*/
|
||||||
AccessControlContext optimize() {
|
AccessControlContext optimize() {
|
||||||
// the assigned (privileged or inherited) context
|
// the assigned (privileged or inherited) context
|
||||||
AccessControlContext acc;
|
AccessControlContext acc;
|
||||||
|
DomainCombiner combiner = null;
|
||||||
|
AccessControlContext parent = null;
|
||||||
|
Permission[] permissions = null;
|
||||||
|
|
||||||
if (isPrivileged) {
|
if (isPrivileged) {
|
||||||
acc = privilegedContext;
|
acc = privilegedContext;
|
||||||
|
if (acc != null) {
|
||||||
|
/*
|
||||||
|
* If the context is from a limited scope doPrivileged() then
|
||||||
|
* copy the permissions and parent fields out of the wrapper
|
||||||
|
* context that was created to hold them.
|
||||||
|
*/
|
||||||
|
if (acc.isWrapped) {
|
||||||
|
permissions = acc.permissions;
|
||||||
|
parent = acc.parent;
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
acc = AccessController.getInheritedAccessControlContext();
|
acc = AccessController.getInheritedAccessControlContext();
|
||||||
|
if (acc != null) {
|
||||||
|
/*
|
||||||
|
* If the inherited context is constrained by a limited scope
|
||||||
|
* doPrivileged() then set it as our parent so we will process
|
||||||
|
* the non-domain-related state.
|
||||||
|
*/
|
||||||
|
if (acc.isLimited) {
|
||||||
|
parent = acc;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// this.context could be null if only system code is on the stack;
|
// this.context could be null if only system code is on the stack;
|
||||||
@ -393,53 +564,98 @@ public final class AccessControlContext {
|
|||||||
// acc.context could be null if only system code was involved;
|
// acc.context could be null if only system code was involved;
|
||||||
// in that case, ignore the assigned context
|
// in that case, ignore the assigned context
|
||||||
boolean skipAssigned = (acc == null || acc.context == null);
|
boolean skipAssigned = (acc == null || acc.context == null);
|
||||||
|
ProtectionDomain[] assigned = (skipAssigned) ? null : acc.context;
|
||||||
|
ProtectionDomain[] pd;
|
||||||
|
|
||||||
|
// if there is no enclosing limited privilege scope on the stack or
|
||||||
|
// inherited from a parent thread
|
||||||
|
boolean skipLimited = ((acc == null || !acc.isWrapped) && parent == null);
|
||||||
|
|
||||||
if (acc != null && acc.combiner != null) {
|
if (acc != null && acc.combiner != null) {
|
||||||
// let the assigned acc's combiner do its thing
|
// let the assigned acc's combiner do its thing
|
||||||
return goCombiner(context, acc);
|
if (getDebug() != null) {
|
||||||
|
debug.println("AccessControlContext invoking the Combiner");
|
||||||
|
}
|
||||||
|
|
||||||
|
// No need to clone current and assigned.context
|
||||||
|
// combine() will not update them
|
||||||
|
combiner = acc.combiner;
|
||||||
|
pd = combiner.combine(context, assigned);
|
||||||
|
} else {
|
||||||
|
if (skipStack) {
|
||||||
|
if (skipAssigned) {
|
||||||
|
calculateFields(acc, parent, permissions);
|
||||||
|
return this;
|
||||||
|
} else if (skipLimited) {
|
||||||
|
return acc;
|
||||||
|
}
|
||||||
|
} else if (assigned != null) {
|
||||||
|
if (skipLimited) {
|
||||||
|
// optimization: if there is a single stack domain and
|
||||||
|
// that domain is already in the assigned context; no
|
||||||
|
// need to combine
|
||||||
|
if (context.length == 1 && context[0] == assigned[0]) {
|
||||||
|
return acc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pd = combine(context, assigned);
|
||||||
|
if (skipLimited && !skipAssigned && pd == assigned) {
|
||||||
|
return acc;
|
||||||
|
} else if (skipAssigned && pd == context) {
|
||||||
|
calculateFields(acc, parent, permissions);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// optimization: if neither have contexts; return acc if possible
|
// Reuse existing ACC
|
||||||
// rather than this, because acc might have a combiner
|
this.context = pd;
|
||||||
if (skipAssigned && skipStack) {
|
this.combiner = combiner;
|
||||||
return this;
|
this.isPrivileged = false;
|
||||||
}
|
|
||||||
|
|
||||||
// optimization: if there is no stack context; there is no reason
|
calculateFields(acc, parent, permissions);
|
||||||
// to compress the assigned context, it already is compressed
|
return this;
|
||||||
if (skipStack) {
|
}
|
||||||
return acc;
|
|
||||||
}
|
|
||||||
|
|
||||||
int slen = context.length;
|
|
||||||
|
/*
|
||||||
|
* Combine the current (stack) and assigned domains.
|
||||||
|
*/
|
||||||
|
private static ProtectionDomain[] combine(ProtectionDomain[]current,
|
||||||
|
ProtectionDomain[] assigned) {
|
||||||
|
|
||||||
|
// current could be null if only system code is on the stack;
|
||||||
|
// in that case, ignore the stack context
|
||||||
|
boolean skipStack = (current == null);
|
||||||
|
|
||||||
|
// assigned could be null if only system code was involved;
|
||||||
|
// in that case, ignore the assigned context
|
||||||
|
boolean skipAssigned = (assigned == null);
|
||||||
|
|
||||||
|
int slen = (skipStack) ? 0 : current.length;
|
||||||
|
|
||||||
// optimization: if there is no assigned context and the stack length
|
// optimization: if there is no assigned context and the stack length
|
||||||
// is less then or equal to two; there is no reason to compress the
|
// is less then or equal to two; there is no reason to compress the
|
||||||
// stack context, it already is
|
// stack context, it already is
|
||||||
if (skipAssigned && slen <= 2) {
|
if (skipAssigned && slen <= 2) {
|
||||||
return this;
|
return current;
|
||||||
}
|
}
|
||||||
|
|
||||||
// optimization: if there is a single stack domain and that domain
|
int n = (skipAssigned) ? 0 : assigned.length;
|
||||||
// is already in the assigned context; no need to combine
|
|
||||||
if ((slen == 1) && (context[0] == acc.context[0])) {
|
|
||||||
return acc;
|
|
||||||
}
|
|
||||||
|
|
||||||
int n = (skipAssigned) ? 0 : acc.context.length;
|
|
||||||
|
|
||||||
// now we combine both of them, and create a new context
|
// now we combine both of them, and create a new context
|
||||||
ProtectionDomain pd[] = new ProtectionDomain[slen + n];
|
ProtectionDomain pd[] = new ProtectionDomain[slen + n];
|
||||||
|
|
||||||
// first copy in the assigned context domains, no need to compress
|
// first copy in the assigned context domains, no need to compress
|
||||||
if (!skipAssigned) {
|
if (!skipAssigned) {
|
||||||
System.arraycopy(acc.context, 0, pd, 0, n);
|
System.arraycopy(assigned, 0, pd, 0, n);
|
||||||
}
|
}
|
||||||
|
|
||||||
// now add the stack context domains, discarding nulls and duplicates
|
// now add the stack context domains, discarding nulls and duplicates
|
||||||
outer:
|
outer:
|
||||||
for (int i = 0; i < context.length; i++) {
|
for (int i = 0; i < slen; i++) {
|
||||||
ProtectionDomain sd = context[i];
|
ProtectionDomain sd = current[i];
|
||||||
if (sd != null) {
|
if (sd != null) {
|
||||||
for (int j = 0; j < n; j++) {
|
for (int j = 0; j < n; j++) {
|
||||||
if (sd == pd[j]) {
|
if (sd == pd[j]) {
|
||||||
@ -453,54 +669,48 @@ public final class AccessControlContext {
|
|||||||
// if length isn't equal, we need to shorten the array
|
// if length isn't equal, we need to shorten the array
|
||||||
if (n != pd.length) {
|
if (n != pd.length) {
|
||||||
// optimization: if we didn't really combine anything
|
// optimization: if we didn't really combine anything
|
||||||
if (!skipAssigned && n == acc.context.length) {
|
if (!skipAssigned && n == assigned.length) {
|
||||||
return acc;
|
return assigned;
|
||||||
} else if (skipAssigned && n == slen) {
|
} else if (skipAssigned && n == slen) {
|
||||||
return this;
|
return current;
|
||||||
}
|
}
|
||||||
ProtectionDomain tmp[] = new ProtectionDomain[n];
|
ProtectionDomain tmp[] = new ProtectionDomain[n];
|
||||||
System.arraycopy(pd, 0, tmp, 0, n);
|
System.arraycopy(pd, 0, tmp, 0, n);
|
||||||
pd = tmp;
|
pd = tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
// return new AccessControlContext(pd, false);
|
return pd;
|
||||||
|
|
||||||
// Reuse existing ACC
|
|
||||||
|
|
||||||
this.context = pd;
|
|
||||||
this.combiner = null;
|
|
||||||
this.isPrivileged = false;
|
|
||||||
|
|
||||||
return this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private AccessControlContext goCombiner(ProtectionDomain[] current,
|
|
||||||
AccessControlContext assigned) {
|
|
||||||
|
|
||||||
// the assigned ACC's combiner is not null --
|
/*
|
||||||
// let the combiner do its thing
|
* Calculate the additional domains that could potentially be reached via
|
||||||
|
* limited privilege scope. Mark the context as being subject to limited
|
||||||
|
* privilege scope unless the reachable domains (if any) are already
|
||||||
|
* contained in this domain context (in which case any limited
|
||||||
|
* privilege scope checking would be redundant).
|
||||||
|
*/
|
||||||
|
private void calculateFields(AccessControlContext assigned,
|
||||||
|
AccessControlContext parent, Permission[] permissions)
|
||||||
|
{
|
||||||
|
ProtectionDomain[] parentLimit = null;
|
||||||
|
ProtectionDomain[] assignedLimit = null;
|
||||||
|
ProtectionDomain[] newLimit;
|
||||||
|
|
||||||
// XXX we could add optimizations to 'current' here ...
|
parentLimit = (parent != null)? parent.limitedContext: null;
|
||||||
|
assignedLimit = (assigned != null)? assigned.limitedContext: null;
|
||||||
if (getDebug() != null) {
|
newLimit = combine(parentLimit, assignedLimit);
|
||||||
debug.println("AccessControlContext invoking the Combiner");
|
if (newLimit != null) {
|
||||||
|
if (context == null || !containsAllPDs(newLimit, context)) {
|
||||||
|
this.limitedContext = newLimit;
|
||||||
|
this.permissions = permissions;
|
||||||
|
this.parent = parent;
|
||||||
|
this.isLimited = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// No need to clone current and assigned.context
|
|
||||||
// combine() will not update them
|
|
||||||
ProtectionDomain[] combinedPds = assigned.combiner.combine(
|
|
||||||
current, assigned.context);
|
|
||||||
|
|
||||||
// return new AccessControlContext(combinedPds, assigned.combiner);
|
|
||||||
|
|
||||||
// Reuse existing ACC
|
|
||||||
this.context = combinedPds;
|
|
||||||
this.combiner = assigned.combiner;
|
|
||||||
this.isPrivileged = false;
|
|
||||||
|
|
||||||
return this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks two AccessControlContext objects for equality.
|
* Checks two AccessControlContext objects for equality.
|
||||||
* Checks that <i>obj</i> is
|
* Checks that <i>obj</i> is
|
||||||
@ -520,31 +730,131 @@ public final class AccessControlContext {
|
|||||||
|
|
||||||
AccessControlContext that = (AccessControlContext) obj;
|
AccessControlContext that = (AccessControlContext) obj;
|
||||||
|
|
||||||
|
if (!equalContext(that))
|
||||||
if (context == null) {
|
|
||||||
return (that.context == null);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (that.context == null)
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!(this.containsAllPDs(that) && that.containsAllPDs(this)))
|
if (!equalLimitedContext(that))
|
||||||
return false;
|
|
||||||
|
|
||||||
if (this.combiner == null)
|
|
||||||
return (that.combiner == null);
|
|
||||||
|
|
||||||
if (that.combiner == null)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (!this.combiner.equals(that.combiner))
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean containsAllPDs(AccessControlContext that) {
|
/*
|
||||||
|
* Compare for equality based on state that is free of limited
|
||||||
|
* privilege complications.
|
||||||
|
*/
|
||||||
|
private boolean equalContext(AccessControlContext that) {
|
||||||
|
if (!equalPDs(this.context, that.context))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (this.combiner == null && that.combiner != null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (this.combiner != null && !this.combiner.equals(that.combiner))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean equalPDs(ProtectionDomain[] a, ProtectionDomain[] b) {
|
||||||
|
if (a == null) {
|
||||||
|
return (b == null);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (b == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!(containsAllPDs(a, b) && containsAllPDs(b, a)))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Compare for equality based on state that is captured during a
|
||||||
|
* call to AccessController.getContext() when a limited privilege
|
||||||
|
* scope is in effect.
|
||||||
|
*/
|
||||||
|
private boolean equalLimitedContext(AccessControlContext that) {
|
||||||
|
if (that == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If neither instance has limited privilege scope then we're done.
|
||||||
|
*/
|
||||||
|
if (!this.isLimited && !that.isLimited)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If only one instance has limited privilege scope then we're done.
|
||||||
|
*/
|
||||||
|
if (!(this.isLimited && that.isLimited))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Wrapped instances should never escape outside the implementation
|
||||||
|
* this class and AccessController so this will probably never happen
|
||||||
|
* but it only makes any sense to compare if they both have the same
|
||||||
|
* isWrapped state.
|
||||||
|
*/
|
||||||
|
if ((this.isWrapped && !that.isWrapped) ||
|
||||||
|
(!this.isWrapped && that.isWrapped)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.permissions == null && that.permissions != null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (this.permissions != null && that.permissions == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!(this.containsAllLimits(that) && that.containsAllLimits(this)))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Skip through any wrapped contexts.
|
||||||
|
*/
|
||||||
|
AccessControlContext thisNextPC = getNextPC(this);
|
||||||
|
AccessControlContext thatNextPC = getNextPC(that);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The protection domains and combiner of a privilegedContext are
|
||||||
|
* not relevant because they have already been included in the context
|
||||||
|
* of this instance by optimize() so we only care about any limited
|
||||||
|
* privilege state they may have.
|
||||||
|
*/
|
||||||
|
if (thisNextPC == null && thatNextPC != null && thatNextPC.isLimited)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (thisNextPC != null && !thisNextPC.equalLimitedContext(thatNextPC))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (this.parent == null && that.parent != null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (this.parent != null && !this.parent.equals(that.parent))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Follow the privilegedContext link making our best effort to skip
|
||||||
|
* through any wrapper contexts.
|
||||||
|
*/
|
||||||
|
private static AccessControlContext getNextPC(AccessControlContext acc) {
|
||||||
|
while (acc != null && acc.privilegedContext != null) {
|
||||||
|
acc = acc.privilegedContext;
|
||||||
|
if (!acc.isWrapped)
|
||||||
|
return acc;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean containsAllPDs(ProtectionDomain[] thisContext,
|
||||||
|
ProtectionDomain[] thatContext) {
|
||||||
boolean match = false;
|
boolean match = false;
|
||||||
|
|
||||||
//
|
//
|
||||||
// ProtectionDomains within an ACC currently cannot be null
|
// ProtectionDomains within an ACC currently cannot be null
|
||||||
// and this is enforced by the constructor and the various
|
// and this is enforced by the constructor and the various
|
||||||
@ -552,17 +862,17 @@ public final class AccessControlContext {
|
|||||||
// to support the notion of a null PD and therefore this logic continues
|
// to support the notion of a null PD and therefore this logic continues
|
||||||
// to support that notion.
|
// to support that notion.
|
||||||
ProtectionDomain thisPd;
|
ProtectionDomain thisPd;
|
||||||
for (int i = 0; i < context.length; i++) {
|
for (int i = 0; i < thisContext.length; i++) {
|
||||||
match = false;
|
match = false;
|
||||||
if ((thisPd = context[i]) == null) {
|
if ((thisPd = thisContext[i]) == null) {
|
||||||
for (int j = 0; (j < that.context.length) && !match; j++) {
|
for (int j = 0; (j < thatContext.length) && !match; j++) {
|
||||||
match = (that.context[j] == null);
|
match = (thatContext[j] == null);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Class<?> thisPdClass = thisPd.getClass();
|
Class<?> thisPdClass = thisPd.getClass();
|
||||||
ProtectionDomain thatPd;
|
ProtectionDomain thatPd;
|
||||||
for (int j = 0; (j < that.context.length) && !match; j++) {
|
for (int j = 0; (j < thatContext.length) && !match; j++) {
|
||||||
thatPd = that.context[j];
|
thatPd = thatContext[j];
|
||||||
|
|
||||||
// Class check required to avoid PD exposure (4285406)
|
// Class check required to avoid PD exposure (4285406)
|
||||||
match = (thatPd != null &&
|
match = (thatPd != null &&
|
||||||
@ -573,6 +883,29 @@ public final class AccessControlContext {
|
|||||||
}
|
}
|
||||||
return match;
|
return match;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean containsAllLimits(AccessControlContext that) {
|
||||||
|
boolean match = false;
|
||||||
|
Permission thisPerm;
|
||||||
|
|
||||||
|
if (this.permissions == null && that.permissions == null)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
for (int i = 0; i < this.permissions.length; i++) {
|
||||||
|
Permission limit = this.permissions[i];
|
||||||
|
Class <?> limitClass = limit.getClass();
|
||||||
|
match = false;
|
||||||
|
for (int j = 0; (j < that.permissions.length) && !match; j++) {
|
||||||
|
Permission perm = that.permissions[j];
|
||||||
|
match = (limitClass.equals(perm.getClass()) &&
|
||||||
|
limit.equals(perm));
|
||||||
|
}
|
||||||
|
if (!match) return false;
|
||||||
|
}
|
||||||
|
return match;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the hash code value for this context. The hash code
|
* Returns the hash code value for this context. The hash code
|
||||||
* is computed by exclusive or-ing the hash code of all the protection
|
* is computed by exclusive or-ing the hash code of all the protection
|
||||||
@ -591,6 +924,7 @@ public final class AccessControlContext {
|
|||||||
if (context[i] != null)
|
if (context[i] != null)
|
||||||
hashCode ^= context[i].hashCode();
|
hashCode ^= context[i].hashCode();
|
||||||
}
|
}
|
||||||
|
|
||||||
return hashCode;
|
return hashCode;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -82,9 +82,15 @@ import sun.reflect.Reflection;
|
|||||||
* else if (caller i is marked as privileged) {
|
* else if (caller i is marked as privileged) {
|
||||||
* if (a context was specified in the call to doPrivileged)
|
* if (a context was specified in the call to doPrivileged)
|
||||||
* context.checkPermission(permission)
|
* context.checkPermission(permission)
|
||||||
* return;
|
* if (limited permissions were specified in the call to doPrivileged) {
|
||||||
|
* for (each limited permission) {
|
||||||
|
* if (the limited permission implies the requested permission)
|
||||||
|
* return;
|
||||||
|
* }
|
||||||
|
* } else
|
||||||
|
* return;
|
||||||
* }
|
* }
|
||||||
* };
|
* }
|
||||||
*
|
*
|
||||||
* // Next, check the context inherited when the thread was created.
|
* // Next, check the context inherited when the thread was created.
|
||||||
* // Whenever a new thread is created, the AccessControlContext at
|
* // Whenever a new thread is created, the AccessControlContext at
|
||||||
@ -101,11 +107,16 @@ import sun.reflect.Reflection;
|
|||||||
* was marked as "privileged" via a <code>doPrivileged</code>
|
* was marked as "privileged" via a <code>doPrivileged</code>
|
||||||
* call without a context argument (see below for information about a
|
* call without a context argument (see below for information about a
|
||||||
* context argument). If that caller's domain has the
|
* context argument). If that caller's domain has the
|
||||||
* specified permission, no further checking is done and
|
* specified permission and at least one limiting permission argument (if any)
|
||||||
|
* implies the requested permission, no further checking is done and
|
||||||
* <code>checkPermission</code>
|
* <code>checkPermission</code>
|
||||||
* returns quietly, indicating that the requested access is allowed.
|
* returns quietly, indicating that the requested access is allowed.
|
||||||
* If that domain does not have the specified permission, an exception
|
* If that domain does not have the specified permission, an exception
|
||||||
* is thrown, as usual.
|
* is thrown, as usual. If the caller's domain had the specified permission
|
||||||
|
* but it was not implied by any limiting permission arguments given in the call
|
||||||
|
* to <code>doPrivileged</code> then the permission checking continues
|
||||||
|
* until there are no more callers or another <code>doPrivileged</code>
|
||||||
|
* call matches the requested permission and returns normally.
|
||||||
*
|
*
|
||||||
* <p> The normal use of the "privileged" feature is as follows. If you
|
* <p> The normal use of the "privileged" feature is as follows. If you
|
||||||
* don't need to return a value from within the "privileged" block, do
|
* don't need to return a value from within the "privileged" block, do
|
||||||
@ -180,6 +191,9 @@ import sun.reflect.Reflection;
|
|||||||
*
|
*
|
||||||
* <p> Be *very* careful in your use of the "privileged" construct, and
|
* <p> Be *very* careful in your use of the "privileged" construct, and
|
||||||
* always remember to make the privileged code section as small as possible.
|
* always remember to make the privileged code section as small as possible.
|
||||||
|
* You can pass <code>Permission</code> arguments to further limit the
|
||||||
|
* scope of the "privilege" (see below).
|
||||||
|
*
|
||||||
*
|
*
|
||||||
* <p> Note that <code>checkPermission</code> always performs security checks
|
* <p> Note that <code>checkPermission</code> always performs security checks
|
||||||
* within the context of the currently executing thread.
|
* within the context of the currently executing thread.
|
||||||
@ -215,7 +229,9 @@ import sun.reflect.Reflection;
|
|||||||
*
|
*
|
||||||
* <p> There are also times where you don't know a priori which permissions
|
* <p> There are also times where you don't know a priori which permissions
|
||||||
* to check the context against. In these cases you can use the
|
* to check the context against. In these cases you can use the
|
||||||
* doPrivileged method that takes a context:
|
* doPrivileged method that takes a context. You can also limit the scope
|
||||||
|
* of the privileged code by passing additional <code>Permission</code>
|
||||||
|
* parameters.
|
||||||
*
|
*
|
||||||
* <pre> {@code
|
* <pre> {@code
|
||||||
* somemethod() {
|
* somemethod() {
|
||||||
@ -223,12 +239,21 @@ import sun.reflect.Reflection;
|
|||||||
* public Object run() {
|
* public Object run() {
|
||||||
* // Code goes here. Any permission checks within this
|
* // Code goes here. Any permission checks within this
|
||||||
* // run method will require that the intersection of the
|
* // run method will require that the intersection of the
|
||||||
* // callers protection domain and the snapshot's
|
* // caller's protection domain and the snapshot's
|
||||||
* // context have the desired permission.
|
* // context have the desired permission. If a requested
|
||||||
|
* // permission is not implied by the limiting FilePermission
|
||||||
|
* // argument then checking of the thread continues beyond the
|
||||||
|
* // caller of doPrivileged.
|
||||||
* }
|
* }
|
||||||
* }, acc);
|
* }, acc, new FilePermission("/temp/*", read));
|
||||||
* ...normal code here...
|
* ...normal code here...
|
||||||
* }}</pre>
|
* }}</pre>
|
||||||
|
* <p> Passing a limiting <code>Permission</code> argument of an instance of
|
||||||
|
* <code>AllPermission</code> is equivalent to calling the equivalent
|
||||||
|
* <code>doPrivileged</code> method without limiting <code>Permission</code>
|
||||||
|
* arguments. Passing a zero length array of <code>Permission</code> disables
|
||||||
|
* the code privileges so that checking always continues beyond the caller of
|
||||||
|
* that <code>doPrivileged</code> method.
|
||||||
*
|
*
|
||||||
* @see AccessControlContext
|
* @see AccessControlContext
|
||||||
*
|
*
|
||||||
@ -334,6 +359,112 @@ public final class AccessController {
|
|||||||
public static native <T> T doPrivileged(PrivilegedAction<T> action,
|
public static native <T> T doPrivileged(PrivilegedAction<T> action,
|
||||||
AccessControlContext context);
|
AccessControlContext context);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Performs the specified <code>PrivilegedAction</code> with privileges
|
||||||
|
* enabled and restricted by the specified
|
||||||
|
* <code>AccessControlContext</code> and with a privilege scope limited
|
||||||
|
* by specified <code>Permission</code> arguments.
|
||||||
|
*
|
||||||
|
* The action is performed with the intersection of the permissions
|
||||||
|
* possessed by the caller's protection domain, and those possessed
|
||||||
|
* by the domains represented by the specified
|
||||||
|
* <code>AccessControlContext</code>.
|
||||||
|
* <p>
|
||||||
|
* If the action's <code>run</code> method throws an (unchecked) exception,
|
||||||
|
* it will propagate through this method.
|
||||||
|
*
|
||||||
|
* @param action the action to be performed.
|
||||||
|
* @param context an <i>access control context</i>
|
||||||
|
* representing the restriction to be applied to the
|
||||||
|
* caller's domain's privileges before performing
|
||||||
|
* the specified action. If the context is
|
||||||
|
* <code>null</code>,
|
||||||
|
* then no additional restriction is applied.
|
||||||
|
* @param perms the <code>Permission</code> arguments which limit the
|
||||||
|
* scope of the caller's privileges. The number of arguments
|
||||||
|
* is variable.
|
||||||
|
*
|
||||||
|
* @return the value returned by the action's <code>run</code> method.
|
||||||
|
*
|
||||||
|
* @throws NullPointerException if action or perms or any element of
|
||||||
|
* perms is <code>null</code>
|
||||||
|
*
|
||||||
|
* @see #doPrivileged(PrivilegedAction)
|
||||||
|
* @see #doPrivileged(PrivilegedExceptionAction,AccessControlContext)
|
||||||
|
*
|
||||||
|
* @since 1.8
|
||||||
|
*/
|
||||||
|
@CallerSensitive
|
||||||
|
public static <T> T doPrivileged(PrivilegedAction<T> action,
|
||||||
|
AccessControlContext context, Permission... perms) {
|
||||||
|
|
||||||
|
AccessControlContext parent = getContext();
|
||||||
|
if (perms == null) {
|
||||||
|
throw new NullPointerException("null permissions parameter");
|
||||||
|
}
|
||||||
|
Class <?> caller = Reflection.getCallerClass();
|
||||||
|
return AccessController.doPrivileged(action, createWrapper(null,
|
||||||
|
caller, parent, context, perms));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Performs the specified <code>PrivilegedAction</code> with privileges
|
||||||
|
* enabled and restricted by the specified
|
||||||
|
* <code>AccessControlContext</code> and with a privilege scope limited
|
||||||
|
* by specified <code>Permission</code> arguments.
|
||||||
|
*
|
||||||
|
* The action is performed with the intersection of the permissions
|
||||||
|
* possessed by the caller's protection domain, and those possessed
|
||||||
|
* by the domains represented by the specified
|
||||||
|
* <code>AccessControlContext</code>.
|
||||||
|
* <p>
|
||||||
|
* If the action's <code>run</code> method throws an (unchecked) exception,
|
||||||
|
* it will propagate through this method.
|
||||||
|
*
|
||||||
|
* <p> This method preserves the current AccessControlContext's
|
||||||
|
* DomainCombiner (which may be null) while the action is performed.
|
||||||
|
*
|
||||||
|
* @param action the action to be performed.
|
||||||
|
* @param context an <i>access control context</i>
|
||||||
|
* representing the restriction to be applied to the
|
||||||
|
* caller's domain's privileges before performing
|
||||||
|
* the specified action. If the context is
|
||||||
|
* <code>null</code>,
|
||||||
|
* then no additional restriction is applied.
|
||||||
|
* @param perms the <code>Permission</code> arguments which limit the
|
||||||
|
* scope of the caller's privileges. The number of arguments
|
||||||
|
* is variable.
|
||||||
|
*
|
||||||
|
* @return the value returned by the action's <code>run</code> method.
|
||||||
|
*
|
||||||
|
* @throws NullPointerException if action or perms or any element of
|
||||||
|
* perms is <code>null</code>
|
||||||
|
*
|
||||||
|
* @see #doPrivileged(PrivilegedAction)
|
||||||
|
* @see #doPrivileged(PrivilegedExceptionAction,AccessControlContext)
|
||||||
|
* @see java.security.DomainCombiner
|
||||||
|
*
|
||||||
|
* @since 1.8
|
||||||
|
*/
|
||||||
|
@CallerSensitive
|
||||||
|
public static <T> T doPrivilegedWithCombiner(PrivilegedAction<T> action,
|
||||||
|
AccessControlContext context, Permission... perms) {
|
||||||
|
|
||||||
|
AccessControlContext parent = getContext();
|
||||||
|
DomainCombiner dc = parent.getCombiner();
|
||||||
|
if (dc == null && context != null) {
|
||||||
|
dc = context.getCombiner();
|
||||||
|
}
|
||||||
|
if (perms == null) {
|
||||||
|
throw new NullPointerException("null permissions parameter");
|
||||||
|
}
|
||||||
|
Class <?> caller = Reflection.getCallerClass();
|
||||||
|
return AccessController.doPrivileged(action, createWrapper(dc, caller,
|
||||||
|
parent, context, perms));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Performs the specified <code>PrivilegedExceptionAction</code> with
|
* Performs the specified <code>PrivilegedExceptionAction</code> with
|
||||||
* privileges enabled. The action is performed with <i>all</i> of the
|
* privileges enabled. The action is performed with <i>all</i> of the
|
||||||
@ -408,6 +539,22 @@ public final class AccessController {
|
|||||||
private static AccessControlContext preserveCombiner(DomainCombiner combiner,
|
private static AccessControlContext preserveCombiner(DomainCombiner combiner,
|
||||||
Class<?> caller)
|
Class<?> caller)
|
||||||
{
|
{
|
||||||
|
return createWrapper(combiner, caller, null, null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a wrapper to contain the limited privilege scope data.
|
||||||
|
*/
|
||||||
|
private static AccessControlContext
|
||||||
|
createWrapper(DomainCombiner combiner, Class<?> caller,
|
||||||
|
AccessControlContext parent, AccessControlContext context,
|
||||||
|
Permission[] perms)
|
||||||
|
{
|
||||||
|
return new AccessControlContext(getCallerPD(caller), combiner, parent,
|
||||||
|
context, perms);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ProtectionDomain getCallerPD(final Class <?> caller) {
|
||||||
ProtectionDomain callerPd = doPrivileged
|
ProtectionDomain callerPd = doPrivileged
|
||||||
(new PrivilegedAction<ProtectionDomain>() {
|
(new PrivilegedAction<ProtectionDomain>() {
|
||||||
public ProtectionDomain run() {
|
public ProtectionDomain run() {
|
||||||
@ -415,18 +562,9 @@ public final class AccessController {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// perform 'combine' on the caller of doPrivileged,
|
return callerPd;
|
||||||
// even if the caller is from the bootclasspath
|
|
||||||
ProtectionDomain[] pds = new ProtectionDomain[] {callerPd};
|
|
||||||
if (combiner == null) {
|
|
||||||
return new AccessControlContext(pds);
|
|
||||||
} else {
|
|
||||||
return new AccessControlContext(combiner.combine(pds, null),
|
|
||||||
combiner);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Performs the specified <code>PrivilegedExceptionAction</code> with
|
* Performs the specified <code>PrivilegedExceptionAction</code> with
|
||||||
* privileges enabled and restricted by the specified
|
* privileges enabled and restricted by the specified
|
||||||
@ -454,7 +592,7 @@ public final class AccessController {
|
|||||||
* @exception NullPointerException if the action is <code>null</code>
|
* @exception NullPointerException if the action is <code>null</code>
|
||||||
*
|
*
|
||||||
* @see #doPrivileged(PrivilegedAction)
|
* @see #doPrivileged(PrivilegedAction)
|
||||||
* @see #doPrivileged(PrivilegedExceptionAction,AccessControlContext)
|
* @see #doPrivileged(PrivilegedAction,AccessControlContext)
|
||||||
*/
|
*/
|
||||||
@CallerSensitive
|
@CallerSensitive
|
||||||
public static native <T> T
|
public static native <T> T
|
||||||
@ -462,6 +600,118 @@ public final class AccessController {
|
|||||||
AccessControlContext context)
|
AccessControlContext context)
|
||||||
throws PrivilegedActionException;
|
throws PrivilegedActionException;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Performs the specified <code>PrivilegedExceptionAction</code> with
|
||||||
|
* privileges enabled and restricted by the specified
|
||||||
|
* <code>AccessControlContext</code> and with a privilege scope limited by
|
||||||
|
* specified <code>Permission</code> arguments.
|
||||||
|
*
|
||||||
|
* The action is performed with the intersection of the permissions
|
||||||
|
* possessed by the caller's protection domain, and those possessed
|
||||||
|
* by the domains represented by the specified
|
||||||
|
* <code>AccessControlContext</code>.
|
||||||
|
* <p>
|
||||||
|
* If the action's <code>run</code> method throws an (unchecked) exception,
|
||||||
|
* it will propagate through this method.
|
||||||
|
*
|
||||||
|
* @param action the action to be performed.
|
||||||
|
* @param context an <i>access control context</i>
|
||||||
|
* representing the restriction to be applied to the
|
||||||
|
* caller's domain's privileges before performing
|
||||||
|
* the specified action. If the context is
|
||||||
|
* <code>null</code>,
|
||||||
|
* then no additional restriction is applied.
|
||||||
|
* @param perms the <code>Permission</code> arguments which limit the
|
||||||
|
* scope of the caller's privileges. The number of arguments
|
||||||
|
* is variable.
|
||||||
|
*
|
||||||
|
* @return the value returned by the action's <code>run</code> method.
|
||||||
|
*
|
||||||
|
* @throws PrivilegedActionException if the specified action's
|
||||||
|
* <code>run</code> method threw a <i>checked</i> exception
|
||||||
|
* @throws NullPointerException if action or perms or any element of
|
||||||
|
* perms is <code>null</code>
|
||||||
|
*
|
||||||
|
* @see #doPrivileged(PrivilegedAction)
|
||||||
|
* @see #doPrivileged(PrivilegedAction,AccessControlContext)
|
||||||
|
*
|
||||||
|
* @since 1.8
|
||||||
|
*/
|
||||||
|
@CallerSensitive
|
||||||
|
public static <T> T doPrivileged(PrivilegedExceptionAction<T> action,
|
||||||
|
AccessControlContext context, Permission... perms)
|
||||||
|
throws PrivilegedActionException
|
||||||
|
{
|
||||||
|
AccessControlContext parent = getContext();
|
||||||
|
if (perms == null) {
|
||||||
|
throw new NullPointerException("null permissions parameter");
|
||||||
|
}
|
||||||
|
Class <?> caller = Reflection.getCallerClass();
|
||||||
|
return AccessController.doPrivileged(action, createWrapper(null, caller, parent, context, perms));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Performs the specified <code>PrivilegedExceptionAction</code> with
|
||||||
|
* privileges enabled and restricted by the specified
|
||||||
|
* <code>AccessControlContext</code> and with a privilege scope limited by
|
||||||
|
* specified <code>Permission</code> arguments.
|
||||||
|
*
|
||||||
|
* The action is performed with the intersection of the permissions
|
||||||
|
* possessed by the caller's protection domain, and those possessed
|
||||||
|
* by the domains represented by the specified
|
||||||
|
* <code>AccessControlContext</code>.
|
||||||
|
* <p>
|
||||||
|
* If the action's <code>run</code> method throws an (unchecked) exception,
|
||||||
|
* it will propagate through this method.
|
||||||
|
*
|
||||||
|
* <p> This method preserves the current AccessControlContext's
|
||||||
|
* DomainCombiner (which may be null) while the action is performed.
|
||||||
|
*
|
||||||
|
* @param action the action to be performed.
|
||||||
|
* @param context an <i>access control context</i>
|
||||||
|
* representing the restriction to be applied to the
|
||||||
|
* caller's domain's privileges before performing
|
||||||
|
* the specified action. If the context is
|
||||||
|
* <code>null</code>,
|
||||||
|
* then no additional restriction is applied.
|
||||||
|
* @param perms the <code>Permission</code> arguments which limit the
|
||||||
|
* scope of the caller's privileges. The number of arguments
|
||||||
|
* is variable.
|
||||||
|
*
|
||||||
|
* @return the value returned by the action's <code>run</code> method.
|
||||||
|
*
|
||||||
|
* @throws PrivilegedActionException if the specified action's
|
||||||
|
* <code>run</code> method threw a <i>checked</i> exception
|
||||||
|
* @throws NullPointerException if action or perms or any element of
|
||||||
|
* perms is <code>null</code>
|
||||||
|
*
|
||||||
|
* @see #doPrivileged(PrivilegedAction)
|
||||||
|
* @see #doPrivileged(PrivilegedAction,AccessControlContext)
|
||||||
|
* @see java.security.DomainCombiner
|
||||||
|
*
|
||||||
|
* @since 1.8
|
||||||
|
*/
|
||||||
|
@CallerSensitive
|
||||||
|
public static <T> T doPrivilegedWithCombiner(PrivilegedExceptionAction<T> action,
|
||||||
|
AccessControlContext context,
|
||||||
|
Permission... perms)
|
||||||
|
throws PrivilegedActionException
|
||||||
|
{
|
||||||
|
AccessControlContext parent = getContext();
|
||||||
|
DomainCombiner dc = parent.getCombiner();
|
||||||
|
if (dc == null && context != null) {
|
||||||
|
dc = context.getCombiner();
|
||||||
|
}
|
||||||
|
if (perms == null) {
|
||||||
|
throw new NullPointerException("null permissions parameter");
|
||||||
|
}
|
||||||
|
Class <?> caller = Reflection.getCallerClass();
|
||||||
|
return AccessController.doPrivileged(action, createWrapper(dc, caller,
|
||||||
|
parent, context, perms));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the AccessControl context. i.e., it gets
|
* Returns the AccessControl context. i.e., it gets
|
||||||
* the protection domains of all the callers on the stack,
|
* the protection domains of all the callers on the stack,
|
||||||
@ -474,6 +724,7 @@ public final class AccessController {
|
|||||||
|
|
||||||
private static native AccessControlContext getStackAccessControlContext();
|
private static native AccessControlContext getStackAccessControlContext();
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the "inherited" AccessControl context. This is the context
|
* Returns the "inherited" AccessControl context. This is the context
|
||||||
* that existed when the thread was created. Package private so
|
* that existed when the thread was created. Package private so
|
||||||
@ -484,9 +735,9 @@ public final class AccessController {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* This method takes a "snapshot" of the current calling context, which
|
* This method takes a "snapshot" of the current calling context, which
|
||||||
* includes the current Thread's inherited AccessControlContext,
|
* includes the current Thread's inherited AccessControlContext and any
|
||||||
* and places it in an AccessControlContext object. This context may then
|
* limited privilege scope, and places it in an AccessControlContext object.
|
||||||
* be checked at a later point, possibly in another thread.
|
* This context may then be checked at a later point, possibly in another thread.
|
||||||
*
|
*
|
||||||
* @see AccessControlContext
|
* @see AccessControlContext
|
||||||
*
|
*
|
||||||
@ -524,7 +775,7 @@ public final class AccessController {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
public static void checkPermission(Permission perm)
|
public static void checkPermission(Permission perm)
|
||||||
throws AccessControlException
|
throws AccessControlException
|
||||||
{
|
{
|
||||||
//System.err.println("checkPermission "+perm);
|
//System.err.println("checkPermission "+perm);
|
||||||
//Thread.currentThread().dumpStack();
|
//Thread.currentThread().dumpStack();
|
||||||
|
215
jdk/test/java/security/AccessController/LimitedDoPrivileged.java
Normal file
215
jdk/test/java/security/AccessController/LimitedDoPrivileged.java
Normal file
@ -0,0 +1,215 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @test
|
||||||
|
* @bug 8014097
|
||||||
|
* @summary Test the limited privilege scope version of doPrivileged
|
||||||
|
*/
|
||||||
|
|
||||||
|
import java.security.*;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
public class LimitedDoPrivileged {
|
||||||
|
/*
|
||||||
|
* Test variations of doPrivileged() and doPrivileged() with a limited privilege scope
|
||||||
|
* in a sandbox with the usual default permission to read the system properties for the
|
||||||
|
* file and path separators.
|
||||||
|
*
|
||||||
|
* By passing in an "assigned" AccessControlContext that has
|
||||||
|
* no default permissions we can test how code privileges are being scoped.
|
||||||
|
*/
|
||||||
|
|
||||||
|
private static final ProtectionDomain domain =
|
||||||
|
new ProtectionDomain(null, null, null, null);
|
||||||
|
private static final AccessControlContext acc =
|
||||||
|
new AccessControlContext(new ProtectionDomain[] { domain });
|
||||||
|
private static final PropertyPermission pathPerm =
|
||||||
|
new PropertyPermission("path.separator", "read");
|
||||||
|
private static final PropertyPermission filePerm =
|
||||||
|
new PropertyPermission("file.separator", "read");
|
||||||
|
|
||||||
|
public static void main(String[] args) throws Exception {
|
||||||
|
/*
|
||||||
|
* Verify that we have the usual default property read permission.
|
||||||
|
*/
|
||||||
|
AccessController.getContext().checkPermission(filePerm);
|
||||||
|
AccessController.getContext().checkPermission(pathPerm);
|
||||||
|
System.out.println("test 1 passed");
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Inject the "no permission" AccessControlContext.
|
||||||
|
*/
|
||||||
|
AccessController.doPrivileged(new PrivilegedAction() {
|
||||||
|
public Object run() {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Verify that we no longer have the "file.separator" permission.
|
||||||
|
*/
|
||||||
|
try {
|
||||||
|
AccessController.getContext().checkPermission(pathPerm);
|
||||||
|
} catch (AccessControlException ace) {
|
||||||
|
System.out.println("test 2 passed");
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Verify that we can give ourselves limited privilege to read
|
||||||
|
* any system property starting with "path.".
|
||||||
|
*/
|
||||||
|
AccessController.doPrivileged
|
||||||
|
(new PrivilegedAction() {
|
||||||
|
public Object run() {
|
||||||
|
AccessController.getContext().checkPermission(pathPerm);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}, null, new PropertyPermission("path.*", "read"));
|
||||||
|
System.out.println("test 3 passed");
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Verify that if we give ourselves limited privilege to read
|
||||||
|
* any system property starting with "path." it won't give us the
|
||||||
|
* the ability to read "file.separator".
|
||||||
|
*/
|
||||||
|
try {
|
||||||
|
AccessController.doPrivileged
|
||||||
|
(new PrivilegedAction() {
|
||||||
|
public Object run() {
|
||||||
|
AccessController.getContext().checkPermission(filePerm);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}, null, new PropertyPermission("path.*", "read"));
|
||||||
|
} catch (AccessControlException ace) {
|
||||||
|
System.out.println("test 4 passed");
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Verify that capturing and passing in the context with no default
|
||||||
|
* system property permission grants will prevent access that succeeded
|
||||||
|
* earlier without the context assignment.
|
||||||
|
*/
|
||||||
|
final AccessControlContext context = AccessController.getContext();
|
||||||
|
try {
|
||||||
|
AccessController.doPrivileged
|
||||||
|
(new PrivilegedAction() {
|
||||||
|
public Object run() {
|
||||||
|
AccessController.getContext().checkPermission(pathPerm);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}, context, new PropertyPermission("path.*", "read"));
|
||||||
|
} catch (AccessControlException ace) {
|
||||||
|
System.out.println("test 5 passed");
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Verify that we can give ourselves full privilege to read
|
||||||
|
* any system property starting with "path.".
|
||||||
|
*/
|
||||||
|
AccessController.doPrivileged
|
||||||
|
(new PrivilegedAction() {
|
||||||
|
public Object run() {
|
||||||
|
AccessController.getContext().checkPermission(pathPerm);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
System.out.println("test 6 passed");
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Verify that capturing and passing in the context with no default
|
||||||
|
* system property permission grants will prevent access that succeeded
|
||||||
|
* earlier without the context assignment.
|
||||||
|
*/
|
||||||
|
try {
|
||||||
|
AccessController.doPrivileged
|
||||||
|
(new PrivilegedAction() {
|
||||||
|
public Object run() {
|
||||||
|
AccessController.getContext().checkPermission(pathPerm);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}, context);
|
||||||
|
} catch (AccessControlException ace) {
|
||||||
|
System.out.println("test 7 passed");
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Verify that we can give ourselves limited privilege to read
|
||||||
|
* any system property starting with "path." when a limited
|
||||||
|
* privilege scope context is captured and passed to a regular
|
||||||
|
* doPrivileged() as an assigned context.
|
||||||
|
*/
|
||||||
|
AccessController.doPrivileged
|
||||||
|
(new PrivilegedAction() {
|
||||||
|
public Object run() {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Capture the limited privilege scope and inject it into the
|
||||||
|
* regular doPrivileged().
|
||||||
|
*/
|
||||||
|
final AccessControlContext limitedContext = AccessController.getContext();
|
||||||
|
AccessController.doPrivileged
|
||||||
|
(new PrivilegedAction() {
|
||||||
|
public Object run() {
|
||||||
|
AccessController.getContext().checkPermission(pathPerm);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}, limitedContext);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}, null, new PropertyPermission("path.*", "read"));
|
||||||
|
System.out.println("test 8 passed");
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Verify that we can give ourselves limited privilege to read
|
||||||
|
* any system property starting with "path." it won't give us the
|
||||||
|
* the ability to read "file.separator" when a limited
|
||||||
|
* privilege scope context is captured and passed to a regular
|
||||||
|
* doPrivileged() as an assigned context.
|
||||||
|
*/
|
||||||
|
AccessController.doPrivileged
|
||||||
|
(new PrivilegedAction() {
|
||||||
|
public Object run() {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Capture the limited privilege scope and inject it into the
|
||||||
|
* regular doPrivileged().
|
||||||
|
*/
|
||||||
|
final AccessControlContext limitedContext = AccessController.getContext();
|
||||||
|
try {
|
||||||
|
AccessController.doPrivileged
|
||||||
|
(new PrivilegedAction() {
|
||||||
|
public Object run() {
|
||||||
|
AccessController.getContext().checkPermission(filePerm);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}, limitedContext);
|
||||||
|
} catch (AccessControlException ace) {
|
||||||
|
System.out.println("test 9 passed");
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}, null, new PropertyPermission("path.*", "read"));
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}, acc);
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user