| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package java.security; |
| |
| /** |
| * This class must be implemented by the vm vendor, or the reference |
| * implementation can be used if the documented native is implemented. |
| * |
| * Checks access to system resources. Supports marking of code as priveleged. |
| * Makes context snapshots to allow checking from other contexts. |
| */ |
| public final class AccessController { |
| static { |
| // Initialize vm-internal caches |
| initializeInternal(); |
| } |
| |
| private static native void initializeInternal(); |
| |
| /** |
| * Prevents this class from being instantiated. |
| */ |
| private AccessController() { |
| } |
| |
| /** |
| * This native must be implemented to use the reference implementation of |
| * this class. It is used by checkPermission() and getContext(), which call |
| * this native with depth = 1. |
| * |
| * Returns an array of ProtectionDomain from the classes on the stack, from |
| * the specified depth up to the first privileged frame, or the end of the |
| * stack if there is not a privileged frame. The array may be larger than |
| * required, but must be null terminated. As bootstrap classes have all |
| * permissions, bootstrap class frames SHOULD be skipped. Bootstrap class |
| * frames MUST be skipped if the ProtectionDomain of bootstrap classes is |
| * null. Duplicate ProtectionDomains SHOULD be removed. |
| * |
| * The first element of the result is the AccessControlContext, which may be |
| * null, either from the privileged frame, or from the current Thread if |
| * there is not a privileged frame. |
| * |
| * A privileged frame is any frame running one of the following methods: |
| * |
| * <code><ul> |
| * <li>java/security/AccessController.doPrivileged(Ljava/security/PrivilegedAction;)Ljava/lang/Object;</li> |
| * <li>java/security/AccessController.doPrivileged(Ljava/security/PrivilegedExceptionAction;)Ljava/lang/Object;</li> |
| * <li>java/security/AccessController.doPrivileged(Ljava/security/PrivilegedAction;Ljava/security/AccessControlContext;)Ljava/lang/Object;</li> |
| * <li>java/security/AccessController.doPrivileged(Ljava/security/PrivilegedExceptionAction;Ljava/security/AccessControlContext;)Ljava/lang/Object;</li> |
| * </ul></code> |
| * |
| * @param depth |
| * The stack depth at which to start. Depth 0 is the current |
| * frame (the caller of this native). |
| * |
| * @return an Object[] where the first element is AccessControlContext, and |
| * the other elements are ProtectionsDomain. |
| */ |
| |
| private static native Object[] getProtectionDomains(int depth); |
| |
| /** |
| * Checks whether the running program is allowed to access the resource |
| * being guarded by the given Permission argument. |
| * |
| * |
| * @param perm |
| * the permission to check |
| * @exception AccessControlException |
| * if access is not allowed. |
| */ |
| public static void checkPermission(Permission perm) |
| throws AccessControlException { |
| if (perm == null) |
| throw new NullPointerException(); |
| Object[] domains = getProtectionDomains(1); |
| AccessControlContext acc = (AccessControlContext) domains[0]; |
| ProtectionDomain[] pDomains = null; |
| if (acc != null && acc.domainCombiner != null) { |
| pDomains = acc.domainCombiner.combine(toArrayOfProtectionDomains( |
| domains, null), acc.domainsArray); |
| } else { |
| pDomains = toArrayOfProtectionDomains(domains, acc); |
| } |
| for (int i = 0, length = pDomains.length; i < length; i++) { |
| if (!pDomains[i].implies(perm)) { |
| throw new AccessControlException("Access Denied " + perm, perm); //$NON-NLS-1$ |
| } |
| } |
| } |
| |
| /** |
| * Used to keep the context live during doPrivileged(). |
| * |
| * @see #doPrivileged(PrivilegedAction, AccessControlContext) |
| */ |
| private static void keepalive(AccessControlContext context) { |
| } |
| |
| /** |
| * Answers the access controller context of the current thread, including |
| * the inherited ones. It basically retrieves all the protection domains |
| * from the calling stack and creates an <code>AccessControlContext</code> |
| * with them. |
| * |
| * @return the access control context of the current thread |
| * @see AccessControlContext |
| */ |
| public static AccessControlContext getContext() { |
| Object[] domains = getProtectionDomains(1); |
| AccessControlContext acc = (AccessControlContext) domains[0]; |
| ProtectionDomain[] pDomains = null; |
| if (acc != null && acc.domainCombiner != null) { |
| pDomains = acc.domainCombiner.combine(toArrayOfProtectionDomains( |
| domains, null), acc.domainsArray); |
| AccessControlContext result = new AccessControlContext(pDomains, |
| false); |
| result.domainCombiner = acc.domainCombiner; |
| return result; |
| } |
| return new AccessControlContext( |
| toArrayOfProtectionDomains(domains, acc), false); |
| } |
| |
| private static ProtectionDomain[] toArrayOfProtectionDomains( |
| Object[] domains, AccessControlContext acc) { |
| int len = 0, size = domains.length - 1; |
| int extra = acc == null ? 0 : acc.domainsArray.length; |
| ProtectionDomain[] answer = new ProtectionDomain[size + extra]; |
| for (int i = 1; i <= size; i++) { |
| boolean found = false; |
| if ((answer[len] = (ProtectionDomain) domains[i]) == null) |
| break; |
| if (acc != null) { |
| for (int j = 0; j < acc.domainsArray.length; j++) { |
| if (answer[len] == acc.domainsArray[j]) { |
| found = true; |
| break; |
| } |
| } |
| } |
| if (!found) |
| len++; |
| } |
| if (len == 0 && acc != null) |
| return acc.domainsArray; |
| else if (len < size) { |
| ProtectionDomain[] copy = new ProtectionDomain[len + extra]; |
| System.arraycopy(answer, 0, copy, 0, len); |
| answer = copy; |
| } |
| if (acc != null) |
| System.arraycopy(acc.domainsArray, 0, answer, len, |
| acc.domainsArray.length); |
| return answer; |
| } |
| |
| /** |
| * Performs the privileged action specified by <code>action</code>. |
| * |
| * When permission checks are made, if the permission has been granted by |
| * all frames below and including the one representing the call to this |
| * method, then the permission is granted. In otherwords, the check stops |
| * here. |
| * |
| * Any unchecked exception generated by this method will propagate up the |
| * chain. |
| * |
| * @param action |
| * the action being performed |
| * @param <T> |
| * the return type for the privileged action |
| * @return the result of evaluating the action |
| * |
| * @see #doPrivileged(PrivilegedAction) |
| */ |
| public static <T> T doPrivileged(PrivilegedAction<T> action) { |
| return action.run(); |
| } |
| |
| /** |
| * Performs the privileged action specified by <code>action</code>. |
| * |
| * When permission checks are made, if the permission has been granted by |
| * all frames below and including the one representing the call to this |
| * method, then the permission is granted iff it is granted by the |
| * AccessControlContext <code>context</code>. In otherwords, no more |
| * checking of the current stack is performed. Instead, the passed in |
| * context is checked. |
| * |
| * Any unchecked exception generated by this method will propagate up the |
| * chain. |
| * |
| * @param action |
| * the action being performed |
| * @param <T> |
| * the return type for the privileged action |
| * @param context |
| * the context being checked for the privileged action |
| * @return the result of evaluating the action |
| * |
| * @see #doPrivileged(PrivilegedAction) |
| */ |
| public static <T> T doPrivileged(PrivilegedAction<T> action, |
| AccessControlContext context) { |
| T result = action.run(); |
| keepalive(context); |
| return result; |
| } |
| |
| /** |
| * Performs the privileged action specified by <code>action</code>. |
| * |
| * When permission checks are made, if the permission has been granted by |
| * all frames below and including the one representing the call to this |
| * method, then the permission is granted. In otherwords, the check stops |
| * here. |
| * |
| * Any unchecked exception generated by this method will propagate up the |
| * chain. However, checked exceptions will be caught an re-thrown as |
| * PrivilegedActionExceptions. |
| * |
| * @param action |
| * the action being performed |
| * @param <T> |
| * the return type for the privileged action |
| * @return the result of evaluating the action |
| * @throws PrivilegedActionException |
| * if a checked exception was thrown |
| * @see #doPrivileged(PrivilegedAction) |
| */ |
| public static <T> T doPrivileged(PrivilegedExceptionAction<T> action) |
| throws PrivilegedActionException { |
| try { |
| return action.run(); |
| } catch (RuntimeException ex) { |
| throw ex; |
| } catch (Exception ex) { |
| throw new PrivilegedActionException(ex); |
| } |
| } |
| |
| /** |
| * Performs the privileged action specified by <code>action</code>. |
| * |
| * When permission checks are made, if the permission has been granted by |
| * all frames below and including the one representing the call to this |
| * method, then the permission is granted iff it is granted by the |
| * AccessControlContext <code>context</code>. In otherwords, no more |
| * checking of the current stack is performed. Instead, the passed in |
| * context is checked. |
| * |
| * Any unchecked exception generated by this method will propagate up the |
| * chain. However, checked exceptions will be caught an re-thrown as |
| * PrivilegedActionExceptions |
| * |
| * @param action |
| * the action being performed |
| * @param <T> |
| * the return type for the privileged action |
| * @param context |
| * the context being checked for the privileged action |
| * @return the result of evaluating the action |
| * @throws PrivilegedActionException |
| * if a checked exception was thrown |
| * |
| * @see #doPrivileged(PrivilegedAction) |
| */ |
| public static <T> T doPrivileged(PrivilegedExceptionAction<T> action, |
| AccessControlContext context) throws PrivilegedActionException { |
| try { |
| T result = action.run(); |
| keepalive(context); |
| return result; |
| } catch (RuntimeException ex) { |
| throw ex; |
| } catch (Exception ex) { |
| throw new PrivilegedActionException(ex); |
| } |
| } |
| |
| } |