2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
18 * Copyright (C) 2008 The Android Open Source Project
20 * Licensed under the Apache License, Version 2.0 (the "License");
21 * you may not use this file except in compliance with the License.
22 * You may obtain a copy of the License at
24 * http://www.apache.org/licenses/LICENSE-2.0
26 * Unless required by applicable law or agreed to in writing, software
27 * distributed under the License is distributed on an "AS IS" BASIS,
28 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
29 * See the License for the specific language governing permissions and
30 * limitations under the License.
33 package java.security;
35 import java.util.ArrayList;
36 import java.util.List;
37 import java.util.WeakHashMap;
38 import org.apache.harmony.security.fortress.SecurityUtils;
41 * {@code AccessController} provides static methods to perform access control
42 * checks and privileged operations.
44 public final class AccessController {
46 private AccessController() {
47 throw new Error("statics only.");
51 * A map used to store a mapping between a given Thread and
52 * AccessControllerContext-s used in successive calls of doPrivileged(). A
53 * WeakHashMap is used to allow automatic wiping of the dead threads from
54 * the map. The thread (normally Thread.currentThread()) is used as a key
55 * for the map, and a value is ArrayList where all AccessControlContext-s
57 * ((ArrayList)contexts.get(Thread.currentThread())).lastElement() - is
58 * reference to the latest context passed to the doPrivileged() call.
62 private static final WeakHashMap<Thread, ArrayList<AccessControlContext>> contexts = new WeakHashMap<Thread, ArrayList<AccessControlContext>>();
65 * Returns the result of executing the specified privileged action. Only the
66 * {@code ProtectionDomain} of the direct caller of this method and the
67 * {@code ProtectionDomain}s of all subsequent classes in the call chain are
68 * checked to be granted the necessary permission if access checks are
71 * If an instance of {@code RuntimeException} is thrown during the execution
72 * of the {@code PrivilegedAction#run()} method of the given action, it will
73 * be propagated through this method.
76 * the action to be executed with privileges
77 * @return the result of executing the privileged action
78 * @throws NullPointerException
79 * if the specified action is {@code null}
81 public static <T> T doPrivileged(PrivilegedAction<T> action) {
83 throw new NullPointerException("action == null");
85 return doPrivileged(action, null);
89 * Returns the result of executing the specified privileged action. The
90 * {@code ProtectionDomain} of the direct caller of this method, the {@code
91 * ProtectionDomain}s of all subsequent classes in the call chain and all
92 * {@code ProtectionDomain}s of the given context are checked to be granted
93 * the necessary permission if access checks are performed.
95 * If an instance of {@code RuntimeException} is thrown during the execution
96 * of the {@code PrivilegedAction#run()} method of the given action, it will
97 * be propagated through this method.
100 * the action to be executed with privileges
102 * the {@code AccessControlContext} whose protection domains are
103 * checked additionally
104 * @return the result of executing the privileged action
105 * @throws NullPointerException
106 * if the specified action is {@code null}
108 public static <T> T doPrivileged(PrivilegedAction<T> action,
109 AccessControlContext context) {
110 if (action == null) {
111 throw new NullPointerException("action == null");
113 List<AccessControlContext> contextsStack = contextsForThread();
114 contextsStack.add(context);
118 contextsStack.remove(contextsStack.size() - 1);
123 * Returns the result of executing the specified privileged action. Only the
124 * {@code ProtectionDomain} of the direct caller of this method and the
125 * {@code ProtectionDomain}s of all subsequent classes in the call chain are
126 * checked to be granted the necessary permission if access checks are
129 * If a checked exception is thrown by the action's run method, it will be
130 * wrapped and propagated through this method.
132 * If an instance of {@code RuntimeException} is thrown during the execution
133 * of the {@code PrivilegedAction#run()} method of the given action, it will
134 * be propagated through this method.
137 * the action to be executed with privileges
138 * @return the result of executing the privileged action
139 * @throws PrivilegedActionException
140 * if the action's run method throws any checked exception
141 * @throws NullPointerException
142 * if the specified action is {@code null}
144 public static <T> T doPrivileged(PrivilegedExceptionAction<T> action)
145 throws PrivilegedActionException {
146 return doPrivileged(action, null);
150 * Returns the result of executing the specified privileged action. The
151 * {@code ProtectionDomain} of the direct caller of this method, the {@code
152 * ProtectionDomain}s of all subsequent classes in the call chain and all
153 * {@code ProtectionDomain}s of the given context are checked to be granted
154 * the necessary permission if access checks are performed.
156 * If a checked exception is thrown by the action's run method, it will be
157 * wrapped and propagated through this method.
159 * If an instance of {@code RuntimeException} is thrown during the execution
160 * of the {@code PrivilegedAction#run()} method of the given action, it will
161 * be propagated through this method.
164 * the action to be executed with privileges
166 * the {@code AccessControlContext} whose protection domains are
167 * checked additionally
168 * @return the result of executing the privileged action
169 * @throws PrivilegedActionException
170 * if the action's run method throws any checked exception
171 * @throws NullPointerException
172 * if the specified action is {@code null}
174 public static <T> T doPrivileged(PrivilegedExceptionAction<T> action,
175 AccessControlContext context) throws PrivilegedActionException {
176 if (action == null) {
177 throw new NullPointerException("action == null");
179 List<AccessControlContext> contextsStack = contextsForThread();
180 contextsStack.add(context);
183 } catch (RuntimeException e) {
184 throw e; // so we don't wrap RuntimeExceptions with PrivilegedActionException
185 } catch (Exception e) {
186 throw new PrivilegedActionException(e);
188 contextsStack.remove(contextsStack.size() - 1);
192 public static <T> T doPrivilegedWithCombiner(PrivilegedAction<T> action) {
193 return doPrivileged(action, newContextSameDomainCombiner());
196 public static <T> T doPrivilegedWithCombiner(PrivilegedExceptionAction<T> action)
197 throws PrivilegedActionException {
198 return doPrivileged(action, newContextSameDomainCombiner());
201 private static AccessControlContext newContextSameDomainCombiner() {
202 List<AccessControlContext> contextsStack = contextsForThread();
203 DomainCombiner domainCombiner = contextsStack.isEmpty()
205 : contextsStack.get(contextsStack.size() - 1).getDomainCombiner();
206 return new AccessControlContext(new ProtectionDomain[0], domainCombiner);
209 private static List<AccessControlContext> contextsForThread() {
210 Thread currThread = Thread.currentThread();
213 * Thread.currentThread() is null when Thread.class is being initialized, and contexts is
214 * null when AccessController.class is still being initialized. In either case, return an
215 * empty list so callers need not worry.
217 if (currThread == null || contexts == null) {
218 return new ArrayList<AccessControlContext>();
221 synchronized (contexts) {
222 ArrayList<AccessControlContext> result = contexts.get(currThread);
223 if (result == null) {
224 result = new ArrayList<AccessControlContext>();
225 contexts.put(currThread, result);
232 * Checks the specified permission against the VM's current security policy.
233 * The check is performed in the context of the current thread. This method
234 * returns silently if the permission is granted, otherwise an {@code
235 * AccessControlException} is thrown.
237 * A permission is considered granted if every {@link ProtectionDomain} in
238 * the current execution context has been granted the specified permission.
239 * If privileged operations are on the execution context, only the {@code
240 * ProtectionDomain}s from the last privileged operation are taken into
243 * This method delegates the permission check to
244 * {@link AccessControlContext#checkPermission(Permission)} on the current
245 * callers' context obtained by {@link #getContext()}.
248 * the permission to check against the policy
249 * @throws AccessControlException
250 * if the specified permission is not granted
251 * @throws NullPointerException
252 * if the specified permission is {@code null}
253 * @see AccessControlContext#checkPermission(Permission)
256 public static void checkPermission(Permission permission)
257 throws AccessControlException {
258 if (permission == null) {
259 throw new NullPointerException("permission == null");
262 getContext().checkPermission(permission);
266 * Returns array of ProtectionDomains from the classes residing on the stack
267 * of the current thread, up to and including the caller of the nearest
268 * privileged frame. Reflection frames are skipped. The returned array is
269 * never null and never contains null elements, meaning that bootstrap
270 * classes are effectively ignored.
272 private static native ProtectionDomain[] getStackDomains();
275 * Returns the {@code AccessControlContext} for the current {@code Thread}
276 * including the inherited access control context of the thread that spawned
277 * the current thread (recursively).
279 * The returned context may be used to perform access checks at a later
280 * point in time, possibly by another thread.
282 * @return the {@code AccessControlContext} for the current {@code Thread}
283 * @see Thread#currentThread
285 public static AccessControlContext getContext() {
287 // duplicates (if any) will be removed in ACC constructor
288 ProtectionDomain[] stack = getStackDomains();
290 Thread currentThread = Thread.currentThread();
291 if (currentThread == null || AccessController.contexts == null) {
292 // Big boo time. No need to check anything ?
293 return new AccessControlContext(stack);
296 List<AccessControlContext> threadContexts = contextsForThread();
298 // if we're in a doPrivileged method, use its context.
299 AccessControlContext that = threadContexts.isEmpty()
300 ? SecurityUtils.getContext(currentThread)
301 : threadContexts.get(threadContexts.size() - 1);
303 if (that != null && that.combiner != null) {
304 ProtectionDomain[] assigned = null;
305 if (that.context != null && that.context.length != 0) {
306 assigned = new ProtectionDomain[that.context.length];
307 System.arraycopy(that.context, 0, assigned, 0, assigned.length);
309 ProtectionDomain[] protectionDomains = that.combiner.combine(stack, assigned);
310 if (protectionDomains == null) {
311 protectionDomains = new ProtectionDomain[0];
313 return new AccessControlContext(protectionDomains, that.combiner);
316 return new AccessControlContext(stack, that);