001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017:
018: package java.security;
019:
020: import java.util.ArrayList;
021: import java.util.WeakHashMap;
022:
023: import org.apache.harmony.security.fortress.SecurityUtils;
024:
025: /**
026: * @com.intel.drl.spec_ref
027: */
028: public final class AccessController {
029:
030: private AccessController() {
031: throw new Error("statics only.");
032: };
033:
034: /**
035: * A map used to store a mapping between a given Thread and
036: * AccessControllerContext-s used in successive calls of doPrivileged(). A
037: * WeakHashMap is used to allow automagical wiping of the dead threads from
038: * the map. The thread (normally Thread.currentThread()) is used as a key
039: * for the map, and a value is ArrayList where all AccessControlContext-s are
040: * stored. ((ArrayList)contexts.get(Thread.currentThread())).lastElement() -
041: * is reference to the latest context passed to the doPrivileged() call.
042: */
043: private static final WeakHashMap<Thread, ArrayList<AccessControlContext>> contexts = new WeakHashMap<Thread, ArrayList<AccessControlContext>>();
044:
045: /**
046: * @com.intel.drl.spec_ref
047: */
048: public static <T> T doPrivileged(PrivilegedAction<T> action) {
049: if (action == null) {
050: throw new NullPointerException("action can not be null");
051: }
052: return doPrivilegedImpl(action, null);
053: }
054:
055: /**
056: * @com.intel.drl.spec_ref
057: */
058: public static <T> T doPrivileged(PrivilegedAction<T> action,
059: AccessControlContext context) {
060: if (action == null) {
061: throw new NullPointerException("action can not be null");
062: }
063: return doPrivilegedImpl(action, context);
064: }
065:
066: /**
067: * @com.intel.drl.spec_ref
068: */
069: public static <T> T doPrivileged(PrivilegedExceptionAction<T> action)
070: throws PrivilegedActionException {
071: if (action == null) {
072: throw new NullPointerException("action can not be null");
073: }
074: return doPrivilegedImpl(action, null);
075: }
076:
077: /**
078: * @com.intel.drl.spec_ref
079: */
080: public static <T> T doPrivileged(
081: PrivilegedExceptionAction<T> action,
082: AccessControlContext context)
083: throws PrivilegedActionException {
084: if (action == null) {
085: throw new NullPointerException("action can not be null");
086: }
087: return doPrivilegedImpl(action, context);
088: }
089:
090: /**
091: * The real implementation of doPrivileged() method.<br>
092: * It pushes the passed context into this thread's contexts stack,
093: * and then invokes <code>action.run()</code>.<br>
094: * The pushed context is then investigated in the {@link getContext()}
095: * which is called in the {@link checkPermission}.
096: */
097: private static <T> T doPrivilegedImpl(
098: PrivilegedExceptionAction<T> action,
099: AccessControlContext context)
100: throws PrivilegedActionException {
101:
102: Thread currThread = Thread.currentThread();
103:
104: ArrayList<AccessControlContext> a = null;
105: try {
106: // currThread==null means that VM warm up is in progress
107: if (currThread != null && contexts != null) {
108: synchronized (contexts) {
109: a = contexts.get(currThread);
110: if (a == null) {
111: a = new ArrayList<AccessControlContext>();
112: contexts.put(currThread, a);
113: }
114: }
115: a.add(context);
116: }
117: return action.run();
118:
119: } catch (Exception ex) {
120: // Errors automagically go throught - they are not catched by this
121: // block
122:
123: // Unchecked exceptions must pass through without modification
124: if (ex instanceof RuntimeException) {
125: throw (RuntimeException) ex;
126: }
127:
128: // All other (==checked) exceptions get wrapped
129: throw new PrivilegedActionException(ex);
130: } finally {
131: if (currThread != null) {
132: // No need to sync() here, as each given 'a' will be accessed
133: // only from one Thread. 'contexts' still need sync() however,
134: // as it's accessed from different threads simultaneously
135: if (a != null) {
136: // it seems I will never have here [v.size() == 0]
137: a.remove(a.size() - 1);
138: }
139: }
140: }
141: }
142:
143: /**
144: * The real implementation of appropriate doPrivileged() method.<br>
145: * It pushes the passed context into this thread's stack of contexts and
146: * then invokes <code>action.run()</code>.<br>
147: * The pushed context is then investigated in the {@link getContext()}
148: * which is called in the {@link checkPermission}.
149: */
150: private static <T> T doPrivilegedImpl(PrivilegedAction<T> action,
151: AccessControlContext context) {
152:
153: Thread currThread = Thread.currentThread();
154:
155: if (currThread == null || contexts == null) {
156: // Big boom time - VM is starting... No need to check permissions:
157: // 1st, I do believe there is no malicious code available here for
158: // this moment
159: // 2d, I cant use currentThread() as a key anyway - when it will
160: // turn into the real Thread, I'll be unable to retrieve the value
161: // stored with 'currThread==null' as a key.
162: return action.run();
163: }
164:
165: ArrayList<AccessControlContext> a = null;
166: try {
167: synchronized (contexts) {
168: a = contexts.get(currThread);
169: if (a == null) {
170: a = new ArrayList<AccessControlContext>();
171: contexts.put(currThread, a);
172: }
173: }
174: a.add(context);
175:
176: return action.run();
177:
178: } finally {
179: // No need to sync() here, as each given 'a' will be accessed
180: // only from one Thread. 'contexts' still need sync() however,
181: // as it's accessed from different threads simultaneously
182: if (a != null) {
183: a.remove(a.size() - 1);
184: }
185: }
186: }
187:
188: /**
189: * @com.intel.drl.spec_ref
190: */
191: public static void checkPermission(Permission perm)
192: throws AccessControlException {
193: if (perm == null) {
194: throw new NullPointerException("permission can not be null");
195: }
196:
197: getContext().checkPermission(perm);
198: }
199:
200: /**
201: * Returns array of ProtectionDomains of classes residing
202: * on the stack of the current thread, up to the caller of nearest
203: * privileged frame; reflection frames are skipped.
204: * The returned array is never null and never contains null elements,
205: * meaning that bootstrap classes are effectively ignored.
206: * @see org.apache.harmony.vm.VMStack.getClasses()
207: */
208: private static native ProtectionDomain[] getStackDomains();
209:
210: /**
211: * @com.intel.drl.spec_ref
212: */
213: public static AccessControlContext getContext() {
214:
215: // duplicates (if any) will be removed in ACC constructor
216: ProtectionDomain[] stack = getStackDomains();
217:
218: Thread currThread = Thread.currentThread();
219: if (currThread == null || contexts == null) {
220: // Big boo time. No need to check anything ?
221: return new AccessControlContext(stack);
222: }
223:
224: ArrayList<AccessControlContext> threadContexts;
225: synchronized (contexts) {
226: threadContexts = contexts.get(currThread);
227: }
228:
229: AccessControlContext that;
230: if ((threadContexts == null) || (threadContexts.size() == 0)) {
231: // We were not in doPrivileged method, so
232: // have inherited context here
233: that = SecurityUtils.getContext(currThread);
234: } else {
235: // We were in doPrivileged method, so
236: // Use context passed to the doPrivileged()
237: that = threadContexts.get(threadContexts.size() - 1);
238: }
239:
240: if (that != null && that.combiner != null) {
241: ProtectionDomain[] assigned = null;
242: if (that.context != null && that.context.length != 0) {
243: assigned = new ProtectionDomain[that.context.length];
244: System.arraycopy(that.context, 0, assigned, 0,
245: assigned.length);
246: }
247: ProtectionDomain[] allpds = that.combiner.combine(stack,
248: assigned);
249: if (allpds == null) {
250: allpds = new ProtectionDomain[0];
251: }
252: return new AccessControlContext(allpds, that.combiner);
253: }
254:
255: return new AccessControlContext(stack, that);
256: }
257: }
|