OSDN Git Service

original
[gb-231r1-is01/Gingerbread_2.3.3_r1_IS01.git] / libcore / luni / src / main / java / java / security / AccessController.java
1 /*
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
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
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.
16  */
17 /*
18  * Copyright (C) 2008 The Android Open Source Project
19  *
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
23  *
24  *      http://www.apache.org/licenses/LICENSE-2.0
25  *
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.
31  */
32
33 package java.security;
34
35 import java.util.ArrayList;
36 import java.util.List;
37 import java.util.WeakHashMap;
38 import org.apache.harmony.security.fortress.SecurityUtils;
39
40 /**
41  * {@code AccessController} provides static methods to perform access control
42  * checks and privileged operations.
43  */
44 public final class AccessController {
45
46     private AccessController() {
47         throw new Error("statics only.");
48     }
49
50     /**
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
56      * are stored.
57      * ((ArrayList)contexts.get(Thread.currentThread())).lastElement() - is
58      * reference to the latest context passed to the doPrivileged() call.
59      *
60      * TODO: ThreadLocal?
61      */
62     private static final WeakHashMap<Thread, ArrayList<AccessControlContext>> contexts = new WeakHashMap<Thread, ArrayList<AccessControlContext>>();
63
64     /**
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
69      * performed.
70      * <p>
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.
74      *
75      * @param action
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}
80      */
81     public static <T> T doPrivileged(PrivilegedAction<T> action) {
82         if (action == null) {
83             throw new NullPointerException("action == null");
84         }
85         return doPrivileged(action, null);
86     }
87
88     /**
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.
94      * <p>
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.
98      *
99      * @param action
100      *            the action to be executed with privileges
101      * @param context
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}
107      */
108     public static <T> T doPrivileged(PrivilegedAction<T> action,
109             AccessControlContext context) {
110         if (action == null) {
111             throw new NullPointerException("action == null");
112         }
113         List<AccessControlContext> contextsStack = contextsForThread();
114         contextsStack.add(context);
115         try {
116             return action.run();
117         } finally {
118             contextsStack.remove(contextsStack.size() - 1);
119         }
120     }
121
122     /**
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
127      * performed.
128      * <p>
129      * If a checked exception is thrown by the action's run method, it will be
130      * wrapped and propagated through this method.
131      * <p>
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.
135      *
136      * @param action
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}
143      */
144     public static <T> T doPrivileged(PrivilegedExceptionAction<T> action)
145             throws PrivilegedActionException {
146         return doPrivileged(action, null);
147     }
148
149     /**
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.
155      * <p>
156      * If a checked exception is thrown by the action's run method, it will be
157      * wrapped and propagated through this method.
158      * <p>
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.
162      *
163      * @param action
164      *            the action to be executed with privileges
165      * @param context
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}
173      */
174     public static <T> T doPrivileged(PrivilegedExceptionAction<T> action,
175             AccessControlContext context) throws PrivilegedActionException {
176         if (action == null) {
177             throw new NullPointerException("action == null");
178         }
179         List<AccessControlContext> contextsStack = contextsForThread();
180         contextsStack.add(context);
181         try {
182             return action.run();
183         } catch (RuntimeException e) {
184             throw e; // so we don't wrap RuntimeExceptions with PrivilegedActionException
185         } catch (Exception e) {
186             throw new PrivilegedActionException(e);
187         } finally {
188             contextsStack.remove(contextsStack.size() - 1);
189         }
190     }
191
192     public static <T> T doPrivilegedWithCombiner(PrivilegedAction<T> action) {
193         return doPrivileged(action, newContextSameDomainCombiner());
194     }
195
196     public static <T> T doPrivilegedWithCombiner(PrivilegedExceptionAction<T> action)
197             throws PrivilegedActionException {
198         return doPrivileged(action, newContextSameDomainCombiner());
199     }
200
201     private static AccessControlContext newContextSameDomainCombiner() {
202         List<AccessControlContext> contextsStack = contextsForThread();
203         DomainCombiner domainCombiner = contextsStack.isEmpty()
204                 ? null
205                 : contextsStack.get(contextsStack.size() - 1).getDomainCombiner();
206         return new AccessControlContext(new ProtectionDomain[0], domainCombiner);
207     }
208
209     private static List<AccessControlContext> contextsForThread() {
210         Thread currThread = Thread.currentThread();
211
212         /*
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.
216          */
217         if (currThread == null || contexts == null) {
218             return new ArrayList<AccessControlContext>();
219         }
220
221         synchronized (contexts) {
222             ArrayList<AccessControlContext> result = contexts.get(currThread);
223             if (result == null) {
224                 result = new ArrayList<AccessControlContext>();
225                 contexts.put(currThread, result);
226             }
227             return result;
228         }
229     }
230
231     /**
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.
236      * <p>
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
241      * account.
242      * <p>
243      * This method delegates the permission check to
244      * {@link AccessControlContext#checkPermission(Permission)} on the current
245      * callers' context obtained by {@link #getContext()}.
246      *
247      * @param permission
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)
254      *
255      */
256     public static void checkPermission(Permission permission)
257             throws AccessControlException {
258         if (permission == null) {
259             throw new NullPointerException("permission == null");
260         }
261
262         getContext().checkPermission(permission);
263     }
264
265     /**
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.
271      */
272     private static native ProtectionDomain[] getStackDomains();
273
274     /**
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).
278      * <p>
279      * The returned context may be used to perform access checks at a later
280      * point in time, possibly by another thread.
281      *
282      * @return the {@code AccessControlContext} for the current {@code Thread}
283      * @see Thread#currentThread
284      */
285     public static AccessControlContext getContext() {
286
287         // duplicates (if any) will be removed in ACC constructor
288         ProtectionDomain[] stack = getStackDomains();
289
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);
294         }
295
296         List<AccessControlContext> threadContexts = contextsForThread();
297
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);
302
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);
308             }
309             ProtectionDomain[] protectionDomains = that.combiner.combine(stack, assigned);
310             if (protectionDomains == null) {
311                 protectionDomains = new ProtectionDomain[0];
312             }
313             return new AccessControlContext(protectionDomains, that.combiner);
314         }
315
316         return new AccessControlContext(stack, that);
317     }
318 }