This document provides background information about what privileged code is and what it is used for, followed by illustrations of the use of the API. It covers the following topics:
The policy for a JDK installation specifies what permissions — which types of system resource accesses — are allowed for code from specified code sources. A code source (of type CodeSource
) essentially consists of the code location (URL) and a reference to the certificates containing the public keys corresponding to the private keys used to sign the code (if it was signed).
The policy is represented by a Policy
object. More specifically, it is represented by a Policy
subclass providing an implementation of the abstract methods in the Policy
class (which is in the java.security
package).
The source location for the policy information used by the Policy
object depends on the Policy
implementation. The Policy
reference implementation obtains its information from policy configuration files. See Default Policy Implementation and Policy File Syntax for information about the Policy
reference implementation and the syntax that must be used in policy files it reads. For information about using the Policy Tool to create a policy file (without needing to know the required syntax), see the Policy Tool documentation (for Unix) (for Windows).
A protection domain encompasses a CodeSource
instance and the permissions granted to code from that CodeSource
, as determined by the security policy currently in effect. Thus, classes signed by the same keys and from the same URL are typically placed in the same domain, and a class belongs to one and only one protection domain. (However, classes signed by the same keys and from the same URL but loaded by separate class loader instances are typically placed in separate domains.) Classes that have the same permissions but are from different code sources belong to different domains.
Currently, all classes shipped with the JDK are loaded with all permissions (this may change in future releases). Most of these classes are placed in a unique system domain. In addition, the extension class loader loads code from JAR files contained in the $JAVA_HOME/jre/lib/ext
directory into separate domains (because the code in these JAR files have unique URLs), but these domains are separate from the unique system domain reserved for classes shipped with the JDK.
Each applet or application runs in its appropriate domain, determined by its code source. For an applet (or an application running under a security manager) to be allowed to perform a secured action (such as reading or writing a file), the applet or application must be granted permission for that particular action.
More specifically, whenever a resource access is attempted, all code traversed by the execution thread up to that point must have permission for that resource access, unless some code on the thread has been marked as privileged. That is, suppose that access control checking occurs in a thread of execution that has a chain of multiple callers. (Think of this as multiple method calls that potentially cross the protection domain boundaries.) When the AccessController
.checkPermission
method is invoked by the most recent caller, the basic algorithm for deciding whether to allow or deny the requested access is as follows: If the code for any caller in the call chain does not have the requested permission, then an AccessControlException
is thrown, unless the following is true: a caller whose code is granted the said permission has been marked as privileged, and all parties subsequently called by this caller (directly or indirectly) have the said permission.
Note that the method AccessController.checkPermission
is normally invoked indirectly through invocations of specific SecurityManager
methods that begin with the word check
such as checkConnect
or through the method SecurityManager.checkPermission
. Normally, these checks only occur if a SecurityManager
has been installed; code checked by the AccessController.checkPermission
method first checks if the method System.getSecurityManager
returns null.
Marking code as privileged enables a piece of trusted code to temporarily enable access to more resources than are available directly to the code that called it. This is necessary in some situations. For example, an application might not be allowed direct access to files that contain fonts, but the system utility to display a document must obtain those fonts, on behalf of the user. The system utility must become privileged in order to obtain the fonts.
The use of the privileged feature is described in the following sections.
If you do not need to return a value from within the privileged
block, your call to doPrivileged
can look like the
following example, which specifies privileged code three ways: in a class that implements the interface PrivilegedAction
, in an anonymous class, and in a lambda expression:
import java.security.*; public class NoReturnNoException { class MyAction implements PrivilegedAction<Void> { public Void run() { // Privileged code goes here, for example: System.loadLibrary("awt"); return null; // nothing to return } } public void somemethod() { MyAction mya = new MyAction(); // Become privileged: AccessController.doPrivileged(mya); // Anonymous class AccessController.doPrivileged(new PrivilegedAction<Void>() { public Void run() { // Privileged code goes here, for example: System.loadLibrary("awt"); return null; // nothing to return } }); // Lambda expression AccessController.doPrivileged((PrivilegedAction<Void>) () -> { // Privileged code goes here, for example: System.loadLibrary("awt"); return null; // nothing to return } ); } public static void main(String... args) { NoReturnNoException myApplication = new NoReturnNoException(); myApplication.somemethod(); } }
The AccessController.doPrivileged
method takes an
object of type java.security.PrivilegedAction
and
invokes its run
method in privileged mode. The
implementation guarantees that privileges will be revoked after the
run
method is executed, even if execution of
doPrivileged
is interrupted by an asynchronous
exception. Note that the invocation of doPrivileged
with a lambda expression explicitly casts the lambda expression as of type PrivilegedAction<Void>
. Another version of the method doPrivileged
exists that takes an object of type PrivilegedExceptionAction
; see Handling Exceptions for more information about this version.
PrivilegedAction
is a functional interface with a single abstract method, named run
, that returns a value of type specified by its type parameter.
Note that this example ignores the return value of the run
method. Also, depending on what privileged code actually consists of, you might have to make some changes due to the way inner classes work. For example, if privileged code throws an exception or attempts to access local variables, then you will have to make some changes, which is described later.
Be very careful in your use of the privileged construct, and always remember to make the privileged code section as small as possible. That is, try to limit the code within the run
method to only what needs to be run with privileges, and do more general things outside the run
method. Also note that the call to doPrivileged
should be made in the code that wants to enable its privileges. Do not be tempted to write a utility class that itself calls doPrivileged
as that could lead to security holes. You can write utility classes for PrivilegedAction
classes though, as shown in the preceding example. See Guideline 9-3: Safely invoke java.security.AccessController.doPrivileged
in Secure Coding Guidelines for the Java Programming Language for more information.
If you need to return a value, then you can do something like the following:
System.out.println( AccessController.doPrivileged((PrivilegedAction<String>) () -> System.getProperty("user.name") ) );
If you are using a lambda expression or anonymous inner class, then any local variables you access must be final
or effectively final. For example:
String lib = "awt"; AccessController.doPrivileged((PrivilegedAction<Void>) () -> { System.loadLibrary(lib); return null; // nothing to return } ); AccessController.doPrivileged(new PrivilegedAction<Void>() { public Object run() { System.loadLibrary(lib); return null; // nothing to return } });
The variable lib
is effectively final because its value has not been modified. For example, suppose you add the following assignment statement after the declaration of the variable lib
:
lib = "swing";
The compiler generates the following errors when it encounters the invocation System.loadLibrary
both in the lambda expression and the anonymous class:
error: local variables referenced from a lambda expression must be final or effectively final
error: local variables referenced from an inner class must be final or effectively final
See Accessing Members of an Enclosing Class in Local Classes for more information.
If there are cases where you cannot make an existing variable
effectively final (because it gets set multiple times), then you
can create a new final
variable right before invoking the
doPrivileged
method, and set that variable equal to the other
variable. For example:
String lib; // The lib variable gets set multiple times so you can't make it // effectively final. // Create a final String that you can use inside of the run method final String fLib = lib; AccessController.doPrivileged((PrivilegedAction<Void>) () -> { System.loadLibrary(fLib); return null; // nothing to return } );
If the action performed in your run
method could
throw a checked exception (one that must be listed in the
throws
clause of a method), then you need to use the
PrivilegedExceptionAction
interface instead of the
PrivilegedAction
interface:
public void processSomefile() throws IOException { try { Path path = FileSystems.getDefault().getPath("somefile"); BufferedReader br = AccessController.doPrivileged( (PrivilegedExceptionAction<BufferedReader>) () -> Files.newBufferedReader(path) ); // ... read from file and do something } catch (PrivilegedActionException e) { // e.getException() should be an instance of IOException // as only checked exceptions will be wrapped in a // PrivilegedActionException. throw (IOException) e.getException(); } }
If a checked exception is thrown during execution of the run
method, then it is placed in a PrivilegedActionException
wrapper exception that is then thrown and should be caught by your code, as illustrated in this example.
As of JDK 8, a variant of AccessController.doPrivileged
is available that enables code to assert a subset of its privileges, without preventing the full traversal of the stack to check for other permissions. This variant of the doPrivileged
variant has three parameters, one of which you use to specify this subset of privileges. For example, the following excerpt asserts a privilege to retrieve system properties:
// Returns the value of the specified property. All code // is allowed to read the app.version and app.vendor // properties. public String getProperty(final String prop) { return AccessController.doPrivileged( (PrivilegedAction<String>) () -> System.getProperty(prop), null, new java.util.PropertyPermission("app.version", "read"), new java.util.PropertyPermission("app.vendor", "read") ); }
The first parameter of this version of doPrivileged
is of type java.security.PrivilegedAction
. In this example, the first parameter is a lambda expression that implements the functional interface PrivilegedAction
whose run
method returns the value of the system property specified by the parameter prop
.
The second parameter of this version of doPrivileged
is of type AccessControlContext
. Sometimes you need to perform an additional security check within a different context, such as a worker thread. You can obtain an AccessControlContext
instance from a particular calling context with the method AccessControlContext.getContext
. If you specify null
for this parameter (as in this example), then the invocation of doPrivileged
does not perform any additional security checks.
The third parameter of this version of doPrivileged
is of type Permission...
, which is a varargs parameter. This means that you can specify one or more Permission
parameters or an array of Permission
objects, as in Permission[]
. In this example, the invocation of doPrivileged
can retrieve the properties app.version
and app.vendor
.
You can use this three parameter variant of doPrivileged
in a mode of least privilege or a mode of more privilege.
The typical use case of the doPrivileged
method is to enable the method that invokes it to perform one or more actions that require permission checks without requiring the callers of the current method to have all the necessary permissions. For example, the current method might need to open a file or make a network request for its own internal implementation purposes.
Before JDK 8, calls to doPrivileged
methods had only two parameters. They worked by granting temporary privileges to the calling method
and stopping the normal full traversal of the stack for access checking when it reached that class, rather than continuing up the call stack where it might reach a method whose defining class does not have the required permission. Typically, the class that is calling doPrivileged
might have additional permissions that are not required in that code path and which might also be missing from some caller classes.
Normally, these extra permissions are not exercised at runtime. Not elevating
them through use of doPrivileged
helps to block exploitation of any incorrect code that could perform unintended actions. This is especially true when the PrivilegedAction
is more complex than usual, or when it calls code outside the class or package boundary that might evolve independently over time.
The three-parameter variant of doPrivileged
is generally safer to use because it avoids unnecessarily elevating permissions that are not intended to be required. However, it executes less efficiently so simple or performance-critical code paths might choose not to use it.
Sometimes when coding the current method, you want to temporarily extend the permission of the calling method to perform an action. For example, a framework I/O API might have a general purpose method for opening files of a particular data format. This API would take a normal file path parameter and use it to open an underlying FileInputStream
using the calling code's permissions. However, this might also allow any caller to open the data files in a special directory that contains some standard demonstration samples.
The callers of this API could be directly granted a FilePermission
for read access. However, it might not be convenient or possible for the security policy of the calling code to be updated. For example, the calling code could be a sandboxed applet.
One way to implement this is for the code to check the incoming path and determine if it refers to a file in the special directory. If it does, then it would call doPrivileged
, enabling all permissions, then open the file inside the PrivilegedAction
. If the file was not in the special directory, the code would open the file without using doPrivileged
.
This technique requires the implementation to carefully handle the requested file path to determine if it refers to the special shared directory. The file path must be canonicalized before calling doPrivileged
so that any relative path will be processed (and permission to read the user.dir
system property will be checked) prior to determining if the path refers to a file in the special directory. It must also prevent malicious "../" path elements meant to escape out of the special directory.
A simpler and better implementation would use the variant of doPrivileged
with the third parameter. It would pass a FilePermission
with read access to the special directory as the third parameter. Then any manipulation of the file would be inside the PrivilegedAction
. This implementation is simpler and much less prone to contain a security flaw.
One subtlety that must be considered is the interaction of this API with reflection. The doPrivileged
method can be invoked reflectively using java.lang.reflect.Method.invoke
. In this case, the privileges granted in privileged mode are not those of Method.invoke
but of the non-reflective code that invoked it. Otherwise, system privileges could erroneously (or maliciously) be conferred on user code. Note that similar requirements exist when using reflection in the existing API.