/** Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.*********************/package java.security;import java.util.ArrayList;import java.util.List;import sun.security.util.Debug;import sun.security.util.FilePermCompat;import sun.security.util.SecurityConstants;/*** An AccessControlContext is used to make system resource access decisions* based on the context it encapsulates.** <p>More specifically, it encapsulates a context and* has a single method, {@code checkPermission},* that is equivalent to the {@code checkPermission} method* in the AccessController class, with one difference: The AccessControlContext* {@code checkPermission} method makes access decisions based on the* context it encapsulates,* rather than that of the current execution thread.** <p>Thus, the purpose of AccessControlContext is for those situations where* a security check that should be made within a given context* actually needs to be done from within a* <i>different</i> context (for example, from within a worker thread).** <p> An AccessControlContext is created by calling the* {@code AccessController.getContext} method.* The {@code getContext} method takes a "snapshot"* of the current calling context, and places* it in an AccessControlContext object, which it returns. A sample call is* the following:** <pre>* AccessControlContext acc = AccessController.getContext()* </pre>** <p>* Code within a different context can subsequently call the* {@code checkPermission} method on the* previously-saved AccessControlContext object. A sample call is the* following:** <pre>* acc.checkPermission(permission)* </pre>** @see AccessController** @author Roland Schemers* @since 1.2*/public final class AccessControlContext {private ProtectionDomain[] context;// isPrivileged and isAuthorized are referenced by the VM - do not remove// or change their namesprivate boolean isPrivileged;private boolean isAuthorized = false;// Note: This field is directly used by the virtual machine// native codes. Don't touch it.private AccessControlContext privilegedContext;private DomainCombiner combiner = null;// limited privilege scopeprivate 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 Debug debug = null;static Debug getDebug(){if (debugInit)return debug;else {if (Policy.isSet()) {debug = Debug.getInstance("access");debugInit = true;}return debug;}}/*** Create an AccessControlContext with the given array of ProtectionDomains.* Context must not be null. Duplicate domains will be removed from the* context.** @param context the ProtectionDomains associated with this context.* The non-duplicate domains are copied from the array. Subsequent* changes to the array will not affect this AccessControlContext.* @throws NullPointerException if {@code context} is {@code null}*/public AccessControlContext(ProtectionDomain[] context){if (context.length == 0) {this.context = null;} else if (context.length == 1) {if (context[0] != null) {this.context = context.clone();} else {this.context = null;}} else {List<ProtectionDomain> v = new ArrayList<>(context.length);for (int i =0; i< context.length; i++) {if ((context[i] != null) && (!v.contains(context[i])))v.add(context[i]);}if (!v.isEmpty()) {this.context = new ProtectionDomain[v.size()];this.context = v.toArray(this.context);}}}/*** Create a new {@code AccessControlContext} with the given* {@code AccessControlContext} and {@code DomainCombiner}.* This constructor associates the provided* {@code DomainCombiner} with the provided* {@code AccessControlContext}.** @param acc the {@code AccessControlContext} associated* with the provided {@code DomainCombiner}.** @param combiner the {@code DomainCombiner} to be associated* with the provided {@code AccessControlContext}.** @exception NullPointerException if the provided* {@code context} is {@code null}.** @exception SecurityException if a security manager is installed and the* caller does not have the "createAccessControlContext"* {@link SecurityPermission}* @since 1.3*/public AccessControlContext(AccessControlContext acc,DomainCombiner combiner) {this(acc, combiner, false);}/*** package private to allow calls from ProtectionDomain without performing* the security check for {@linkplain SecurityConstants#CREATE_ACC_PERMISSION}* permission*/AccessControlContext(AccessControlContext acc,DomainCombiner combiner,boolean preauthorized) {if (!preauthorized) {SecurityManager sm = System.getSecurityManager();if (sm != null) {sm.checkPermission(SecurityConstants.CREATE_ACC_PERMISSION);this.isAuthorized = true;}} else {this.isAuthorized = true;}this.context = acc.context;// we do not need to run the combine method on the// provided ACC. it was already "combined" when the// context was originally retrieved.//// at this point in time, we simply throw away the old// combiner and use the newly provided one.this.combiner = combiner;}/*** 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 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 (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;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;}// Add altPath into permission for compatibility.tmp[i] = FilePermCompat.newPermPlusAltPath(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()}this.isAuthorized = true;}/*** package private constructor for AccessController.getContext()*/AccessControlContext(ProtectionDomain[] context,boolean isPrivileged){this.context = context;this.isPrivileged = isPrivileged;this.isAuthorized = true;}/*** Constructor for JavaSecurityAccess.doIntersectionPrivilege()*/AccessControlContext(ProtectionDomain[] context,AccessControlContext privilegedContext){this.context = context;this.privilegedContext = privilegedContext;this.isPrivileged = true;}/*** Returns this context's context.*/ProtectionDomain[] getContext() {return context;}/*** Returns true if this context is privileged.*/boolean isPrivileged(){return isPrivileged;}/*** get the assigned combiner from the privileged or inherited context*/DomainCombiner getAssignedCombiner() {AccessControlContext acc;if (isPrivileged) {acc = privilegedContext;} else {acc = AccessController.getInheritedAccessControlContext();}if (acc != null) {return acc.combiner;}return null;}/*** Get the {@code DomainCombiner} associated with this* {@code AccessControlContext}.** @return the {@code DomainCombiner} associated with this* {@code AccessControlContext}, or {@code null}* if there is none.** @exception SecurityException if a security manager is installed and* the caller does not have the "getDomainCombiner"* {@link SecurityPermission}* @since 1.3*/public DomainCombiner getDomainCombiner() {SecurityManager sm = System.getSecurityManager();if (sm != null) {sm.checkPermission(SecurityConstants.GET_COMBINER_PERMISSION);}return getCombiner();}/*** package private for AccessController*/DomainCombiner getCombiner() {return combiner;}boolean isAuthorized() {return isAuthorized;}/*** Determines whether the access request indicated by the* specified permission should be allowed or denied, based on* the security policy currently in effect, and the context in* this object. The request is allowed only if every ProtectionDomain* in the context implies the permission. Otherwise the request is* denied.** <p>* This method quietly returns if the access request* is permitted, or throws a suitable AccessControlException otherwise.** @param perm the requested permission.** @exception AccessControlException if the specified permission* is not permitted, based on the current security policy and the* context encapsulated by this object.* @exception NullPointerException if the permission to check for is null.*/public void checkPermission(Permission perm)throws AccessControlException{boolean dumpDebug = false;if (perm == null) {throw new NullPointerException("permission can't be null");}if (getDebug() != null) {// If "codebase" is not specified, we dump the info by default.dumpDebug = !Debug.isOn("codebase=");if (!dumpDebug) {// If "codebase" is specified, only dump if the specified code// value is in the stack.for (int i = 0; context != null && i < context.length; i++) {if (context[i].getCodeSource() != null &&context[i].getCodeSource().getLocation() != null &&Debug.isOn("codebase=" + context[i].getCodeSource().getLocation().toString())) {dumpDebug = true;break;}}}dumpDebug &= !Debug.isOn("permission=") ||Debug.isOn("permission=" + perm.getClass().getCanonicalName());if (dumpDebug && Debug.isOn("stack")) {Thread.dumpStack();}if (dumpDebug && Debug.isOn("domain")) {if (context == null) {debug.println("domain (context is null)");} else {for (int i=0; i< context.length; i++) {debug.println("domain "+i+" "+context[i]);}}}}/** iterate through the ProtectionDomains in the context.* Stop at the first one that doesn't allow the* requested permission (throwing an exception).**//* if ctxt is null, all we had on the stack were system domains,or the first domain was a Privileged system domain. Thisis to make the common case for system code very fast */if (context == null) {checkPermission2(perm);return;}for (int i=0; i< context.length; i++) {if (context[i] != null && !context[i].impliesWithAltFilePerm(perm)) {if (dumpDebug) {debug.println("access denied " + perm);}if (Debug.isOn("failure") && debug != null) {// Want to make sure this is always displayed for failure,// but do not want to display again if already displayed// above.if (!dumpDebug) {debug.println("access denied " + perm);}Thread.dumpStack();final ProtectionDomain pd = context[i];final Debug db = debug;AccessController.doPrivileged (new PrivilegedAction<>() {public Void run() {db.println("domain that failed "+pd);return null;}});}throw new AccessControlException("access denied "+perm, perm);}}// allow if all of them allowed accessif (dumpDebug) {debug.println("access allowed "+perm);}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* 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() {// the assigned (privileged or inherited) contextAccessControlContext acc;DomainCombiner combiner = null;AccessControlContext parent = null;Permission[] permissions = null;if (isPrivileged) {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 {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;// in that case, ignore the stack contextboolean skipStack = (context == null);// acc.context could be null if only system code was involved;// in that case, ignore the assigned contextboolean 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 threadboolean skipLimited = ((acc == null || !acc.isWrapped) && parent == null);if (acc != null && acc.combiner != null) {// let the assigned acc's combiner do its thingif (getDebug() != null) {debug.println("AccessControlContext invoking the Combiner");}// No need to clone current and assigned.context// combine() will not update themcombiner = 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 combineif (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;}}// Reuse existing ACCthis.context = pd;this.combiner = combiner;this.isPrivileged = false;calculateFields(acc, parent, permissions);return this;}/** 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 contextboolean skipStack = (current == null);// assigned could be null if only system code was involved;// in that case, ignore the assigned contextboolean skipAssigned = (assigned == null);int slen = (skipStack) ? 0 : current.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// stack context, it already isif (skipAssigned && slen <= 2) {return current;}int n = (skipAssigned) ? 0 : assigned.length;// now we combine both of them, and create a new contextProtectionDomain[] pd = new ProtectionDomain[slen + n];// first copy in the assigned context domains, no need to compressif (!skipAssigned) {System.arraycopy(assigned, 0, pd, 0, n);}// now add the stack context domains, discarding nulls and duplicatesouter:for (int i = 0; i < slen; i++) {ProtectionDomain sd = current[i];if (sd != null) {for (int j = 0; j < n; j++) {if (sd == pd[j]) {continue outer;}}pd[n++] = sd;}}// if length isn't equal, we need to shorten the arrayif (n != pd.length) {// optimization: if we didn't really combine anythingif (!skipAssigned && n == assigned.length) {return assigned;} else if (skipAssigned && n == slen) {return current;}ProtectionDomain[] tmp = new ProtectionDomain[n];System.arraycopy(pd, 0, tmp, 0, n);pd = tmp;}return pd;}/** 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;parentLimit = (parent != null)? parent.limitedContext: null;assignedLimit = (assigned != null)? assigned.limitedContext: null;newLimit = combine(parentLimit, assignedLimit);if (newLimit != null) {if (context == null || !containsAllPDs(newLimit, context)) {this.limitedContext = newLimit;this.permissions = permissions;this.parent = parent;this.isLimited = true;}}}/*** Checks two AccessControlContext objects for equality.* Checks that {@code obj} is* an AccessControlContext and has the same set of ProtectionDomains* as this context.** @param obj the object we are testing for equality with this object.* @return true if {@code obj} is an AccessControlContext, and has the* same set of ProtectionDomains as this context, false otherwise.*/public boolean equals(Object obj) {if (obj == this)return true;if (! (obj instanceof AccessControlContext))return false;AccessControlContext that = (AccessControlContext) obj;if (!equalContext(that))return false;if (!equalLimitedContext(that))return false;return true;}/** 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;//// ProtectionDomains within an ACC currently cannot be null// and this is enforced by the constructor and the various// optimize methods. However, historically this logic made attempts// to support the notion of a null PD and therefore this logic continues// to support that notion.ProtectionDomain thisPd;for (int i = 0; i < thisContext.length; i++) {match = false;if ((thisPd = thisContext[i]) == null) {for (int j = 0; (j < thatContext.length) && !match; j++) {match = (thatContext[j] == null);}} else {Class<?> thisPdClass = thisPd.getClass();ProtectionDomain thatPd;for (int j = 0; (j < thatContext.length) && !match; j++) {thatPd = thatContext[j];// Class check required to avoid PD exposure (4285406)match = (thatPd != null &&thisPdClass == thatPd.getClass() && thisPd.equals(thatPd));}}if (!match) return false;}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* is computed by exclusive or-ing the hash code of all the protection* domains in the context together.** @return a hash code value for this context.*/public int hashCode() {int hashCode = 0;if (context == null)return hashCode;for (int i =0; i < context.length; i++) {if (context[i] != null)hashCode ^= context[i].hashCode();}return hashCode;}}
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。