Permissions in the JDK
A permission represents access to a system resource. In order for a resource access to be allowed for an applet (or an application running with a security manager), the corresponding permission must be explicitly granted to the code attempting the access.
WARNING:
The Security Manager and APIs related to it have been deprecated and are subject to removal in a future release. There is no replacement for the Security Manager. See JEP 411 for discussion and alternatives.A permission typically has a name (often referred to as a "target name") and, in some cases, a comma-separated list of one or more actions. For example, the following code creates a FilePermission
object representing read access to the file named abc
in the /tmp
directory:
perm = new java.io.FilePermission("/tmp/abc", "read");
Here, the target name is "/tmp/abc
" and the action string is "read
".
Important:
The previous statement creates a permission object. A permission object represents, but does not grant access to, a system resource. Permission objects are constructed and assigned ("granted") to code based on the policy in effect. When a permission object is assigned to some code, that code is granted the permission to access the system resource specified in the permission object, in the specified manner. A permission object may also be constructed by the current security manager when making access decisions. In this case, the (target) permission object is created based on the requested access, and checked against the permission objects granted to and held by the code making the request.The policy for a Java application environment is represented by a Policy object. In the "JavaPolicy"
Policy implementation, the policy can be specified within one or more policy configuration files. The policy file(s) specify what permissions are allowed for code from specified code sources. The following is a sample policy file entry that grants code from the /home/sysadmin
directory read access to the file /tmp/abc
:
grant codeBase "file:/home/sysadmin/" {
permission java.io.FilePermission "/tmp/abc", "read";
};
To know more about policy file locations and granting permissions in policy files, see Default Policy Implementation and Policy File Syntax.
Technically, 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." See Appendix A: API for Privileged Blocks.
Permission Descriptions and Risks
The following is a list of all built-in JDK permission types. The class summary for each permission type discusses the risks of granting each permission.
- java.awt.AWTPermission
- java.io.FilePermission
- java.io.SerializablePermission
- java.lang.RuntimePermission
- java.lang.management.ManagementPermission
- java.lang.reflect.ReflectPermission
- java.net.NetPermission
- java.net.URLPermission
- java.net.SocketPermission
- java.nio.file.LinkPermission
- java.security.AllPermission
- java.security.SecurityPermission
- java.security.UnresolvedPermission
- java.sql.SQLPermission
- java.util.logging.LoggingPermission
- java.util.PropertyPermission
- javax.management.MBeanPermission
- javax.management.MBeanServerPermission
- javax.management.MBeanTrustPermission
- javax.management.remote.SubjectDelegationPermission
- javax.net.ssl.SSLPermission
- javax.security.auth.AuthPermission
- javax.security.auth.PrivateCredentialPermission
- javax.security.auth.kerberos.DelegationPermission
- javax.security.auth.kerberos.ServicePermission
- javax.smartcardio.CardPermission
- javax.sound.sampled.AudioPermission
Note:
See Appendix A: FilePermission Path Name Canonicalization Disabled By Default for important information about a change in how FilePermission path names are canonicalized.
Methods and the Permissions They Require
The following table is a list of methods that require permissions, which SecurityManager method they call, and which permission is checked by the default implementation of that SecurityManager method.
Note:
This list is not complete; other methods exist that require permissions. See the Java SE and JDK API Specification for additional information on methods that throwSecurityException
and the permissions that are required.
In the default SecurityManager
method implementations, a call to a method in the Method column can only be successful if the permission specified in the corresponding entry in the SecurityManager Method column is allowed by the policy currently in effect. For example, consider the following table row:
Method | SecurityManager Method Called | Permission |
---|---|---|
|
checkPermission | java.awt.AWTPermission "accessEventQueue"; |
This table row specifies that a call to the getSystemEventQueue method in the java.awt.Toolkit class results in a call to the checkPermission SecurityManager method, which can only be successful if the following permission is granted to code on the call stack:
java.awt.AWTPermission "accessEventQueue";
The table rows have the following format, where the runtime value of foo
replaces the string {foo}
in the permission name.
Method | SecurityManager Method Called | Permission |
---|---|---|
|
checkXXX | SomePermission "{foo}"; |
As an example, here is one table entry:
Method | SecurityManager Method Called | Permission |
---|---|---|
|
checkRead(String) | java.io.FilePermission "{name}", "read"; |
If the FileInputStream
method (in this case, a constructor) is called with "/test/MyTestFile"
as the name
argument, as in
FileInputStream("/test/MyTestFile");
then in order for the call to succeed, the following permission must be set in the current policy, allowing read access to the file "/test/MyTestFile"
:
java.io.FilePermission "/test/MyTestFile", "read";
More specifically, the permission must either be explicitly set, as in this example, or implied by another permission, such as the following:
java.io.FilePermission "/test/*", "read";
which allows read access to any files in the "/test"
directory.
In some cases, a term in braces is not exactly the same as the name of a specific method argument but is meant to represent the relevant value. Here is an example:
Method | SecurityManager Method Called | Permission |
---|---|---|
java.net.DatagramSocket public synchronized void receive(DatagramPacket p); |
checkAccept({host}, {port}) | java.net.SocketPermission "{host}:{port}", "accept"; |
Here, the appropriate host and port values are calculated by the receive
method and passed to checkAccept
.
In most cases, just the name of the SecurityManager method called is listed. Where the method is one of multiple methods of the same name, the argument types are also listed, for example for checkRead(String)
and checkRead(FileDescriptor)
. In other cases where arguments may be relevant, they are also listed.
The following table is ordered by package name; the methods in classes in the java.awt
package are listed first, followed by methods in classes in the java.beans
package, and so on:
Table 1-4 Methods and the Permissions
Method | SecurityManager Method | Permission |
---|---|---|
|
checkPermission | java.awt.AWTPermission "readDisplayPixels" if this Graphics2D context is drawing to a Component on the display screen and the Composite is a custom object rather than an instance of the AlphaComposite class. Note: The setComposite method is actually abstract and thus can't invoke security checks. Each actual implementation of the method should call the java.lang.SecurityManager checkPermission method with a java.awt.AWTPermission("readDisplayPixels") permission under the conditions noted.
|
|
checkPermission | java.awt.AWTPermission "createRobot" |
|
checkPermission | java.awt.AWTPermission "listenToAllAWTEvents" |
|
checkPrintJobAccess |
Note: The getPrintJob method is actually abstract and thus can't invoke security checks. Each actual implementation of the method should call the java.lang.SecurityManager checkPrintJobAccess method, which is successful only if the |
|
checkPermission |
Note: The getSystemClipboard method is actually abstract and thus can't invoke security checks. Each actual implementation of the method should call the checkPermission method, which is successful only if the |
|
checkPermission | java.awt.AWTPermission "accessEventQueue" |
|
checkPermission | If java.awt.AWTPermission "showWindowWithoutWarningBanner" is set, the window will be displayed without a banner warning that the window was created by an applet. It it's not set, such a banner will be displayed.
|
|
checkPropertiesAccess | java.util.PropertyPermission "*", "read,write" |
|
checkDelete(String) | java.io.FilePermission "{name}", "delete" |
|
checkRead(FileDescriptor) | java.lang.RuntimePermission "readFileDescriptor" |
(where mode is "r" in both RandomAccessFile constructurs) |
checkRead(String) | java.io.FilePermission "{name}", "read" |
|
checkWrite(FileDescriptor) | java.lang.RuntimePermission "writeFileDescriptor" |
|
checkWrite(String) | java.io.FilePermission "{name}", "write" |
|
checkPermission | java.io.SerializablePermission "enableSubstitution" |
|
checkPermission | java.io.SerializablePermission "enableSubclassImplementation" |
(where mode is "rw") |
checkRead(String) and checkWrite(String) | java.io.FilePermission "{name}", "read,write" |
|
checkPermission | If loader is null, and the caller's class loader is not null, then java.lang.RuntimePermission("getClassLoader") |
|
checkPermission | If the caller's class loader is null, or is the same as or an ancestor of the class loader for the class whose class loader is being requested, no permission is needed. Otherwise, java.lang.RuntimePermission "getClassLoader" is required.
|
|
checkMemberAccess(this, Member.DECLARED) and, if this class is in a package, checkPackageAccess({pkgName}) | Default checkMemberAccess does not require any permissions if "this" class's class loader is the same as that of the caller. Otherwise, it requires java.lang.RuntimePermission "accessDeclaredMembers" . If this class is in a package, java.lang.RuntimePermission "accessClassInPackage.{pkgName}" is also required.
|
|
checkMemberAccess(this, Member.PUBLIC) and, if class is in a package, checkPackageAccess({pkgName}) | Default checkMemberAccess does not require any permissions when the access type is Member.PUBLIC. If this class is in a package, java.lang.RuntimePermission "accessClassInPackage.{pkgName}" is required.
|
|
checkPermission | java.lang.RuntimePermission "getProtectionDomain" |
|
checkCreateClassLoader | java.lang.RuntimePermission "createClassLoader" |
|
checkPermission | If the caller's class loader is null, or is the same as or an ancestor of the class loader for the class whose class loader is being requested, no permission is needed. Otherwise, java.lang.RuntimePermission "getClassLoader" is required.
|
|
checkExec | java.io.FilePermission "{command}", "execute" |
|
checkPermission | java.lang.RuntimePermission "shutdownHooks" |
|
checkLink({libName}) where {libName} is the lib, filename or libname argument | java.lang.RuntimePermission "loadLibrary.{libName}" |
java.lang.SecurityManager methods |
checkPermission | See Table 1-5. |
|
checkPropertiesAccess | java.util.PropertyPermission "*", "read,write" |
|
checkPropertyAccess | java.util.PropertyPermission "{key}", "read" |
|
checkPermission | java.lang.RuntimePermission "setIO" |
|
checkPermission | java.util.PropertyPermission "{key}", "write" |
|
checkPermission | java.lang.RuntimePermission "setSecurityManager" |
|
checkPermission | If the caller's class loader is null, or is the same as or an ancestor of the context class loader for the thread whose context class loader is being requested, no permission is needed. Otherwise, java.lang.RuntimePermission "getClassLoader" is required.
|
|
checkPermission | java.lang.RuntimePermission "setContextClassLoader" |
|
checkAccess(this) | java.lang.RuntimePermission "modifyThread" |
|
checkAccess({threadGroup}) | java.lang.RuntimePermission "modifyThreadGroup" |
|
checkAccess({parentThreadGroup}) | java.lang.RuntimePermission "modifyThreadGroup" |
|
checkAccess(this) for ThreadGroup methods, or checkAccess(group) for Thread methods | java.lang.RuntimePermission "modifyThreadGroup" |
|
checkAccess(this) | Requires java.lang.RuntimePermission "modifyThreadGroup" . Also requires java.lang.RuntimePermission "modifyThread" , since the java.lang.Thread interrupt() method is called for each thread in the thread group and in all of its subgroups. See the Thread interrupt() method.
|
|
checkPermission | java.lang.reflect.ReflectPermission "suppressAccessChecks" |
|
checkPermission | java.net.NetPermission "requestPasswordAuthentication" |
|
checkPermission | java.net.NetPermission "setDefaultAuthenticator" |
|
checkMulticast(InetAddress) | java.net.SocketPermission( mcastaddr.getHostAddress(), "accept,connect") |
|
checkMulticast(p.getAddress()) or checkConnect( p.getAddress().getHostAddress(), p.getPort()) |
|
|
checkMulticast(p.getAddress(), ttl) or checkConnect( p.getAddress().getHostAddress(), p.getPort()) |
|
|
checkConnect({host}, -1) | java.net.SocketPermission "{host}", "resolve" |
|
checkListen({port}) | java.net.SocketPermission "localhost:{port}","listen"; |
|
checkAccept({host}, {port}) | java.net.SocketPermission "{host}:{port}", "accept" |
|
checkSetFactory | java.lang.RuntimePermission "setFactory" |
|
checkConnect({host}, {port}) | java.net.SocketPermission "{host}:{port}", "connect" |
|
checkAccept({host}, {port}) | java.net.SocketPermission "{host}:{port}", "accept" |
|
checkPermission | java.net.NetPermission "specifyStreamHandler" |
|
checkCreateClassLoader | java.lang.RuntimePermission "createClassLoader" |
|
checkPermission | java.security.SecurityPermission "createAccessControlContext" |
|
checkSecurityAccess("addIdentityCertificate") | java.security.SecurityPermission "addIdentityCertificate" |
|
checkSecurityAccess("removeIdentityCertificate") | java.security.SecurityPermission "removeIdentityCertificate" |
|
checkSecurityAccess("setIdentityInfo") | java.security.SecurityPermission "setIdentityInfo" |
|
checkSecurityAccess("setIdentityPublicKey") | java.security.SecurityPermission "setIdentityPublicKey" |
|
checkSecurityAccess("printIdentity") | java.security.SecurityPermission "printIdentity" |
|
checkSecurityAccess("setSystemScope") | java.security.SecurityPermission "setSystemScope" |
|
checkPermission(this) | This Permission object is the permission checked. |
|
checkPermission | java.security.SecurityPermission "getPolicy" |
|
checkPermission | java.security.SecurityPermission "setPolicy" |
|
checkPermission | java.security.SecurityPermission "createPolicy.{type}" |
|
checkSecurityAccess("clearProviderProperties."+{name}) | java.security.SecurityPermission "clearProviderProperties.{name}" where name is the provider name.
|
|
checkSecurityAccess("putProviderProperty."+{name}) | java.security.SecurityPermission "putProviderProperty.{name}" where name is the provider name.
|
|
checkSecurityAccess("removeProviderProperty."+{name}) | java.security.SecurityPermission "removeProviderProperty.{name}" where name is the provider name.
|
|
checkCreateClassLoader | java.lang.RuntimePermission "createClassLoader" |
|
checkPermission | java.security.SecurityPermission "getProperty.{key}" |
|
checkSecurityAccess("insertProvider."+provider.getName()) | java.security.SecurityPermission "insertProvider.{name}" |
|
checkSecurityAccess("removeProvider."+name) | java.security.SecurityPermission "removeProvider.{name}" |
|
checkSecurityAccess("setProperty."+key) | java.security.SecurityPermission "setProperty.{key}" |
|
checkSecurityAccess("getSignerPrivateKey") | java.security.SecurityPermission "getSignerPrivateKey" |
|
checkSecurityAccess("setSignerKeypair") | java.security.SecurityPermission "setSignerKeypair" |
|
checkPermission | java.sql.SQLPermission "setLog" |
|
checkPermission | java.sql.SQLPermission "setLog" |
|
checkPermission | java.util.PropertyPermission "user.language","write" |
|
checkRead | java.io.FilePermission "{name}","read" |
|
checkPermission | javax.security.auth.AuthPermission "getSubject" |
|
checkPermission | javax.security.auth.AuthPermission "setReadOnly" |
|
checkPermission | javax.security.auth.AuthPermission "doAs" |
|
checkPermission | javax.security.auth.AuthPermission "doAs" |
|
checkPermission | javax.security.auth.AuthPermission "doAsPrivileged" |
|
checkPermission | javax.security.auth.AuthPermission "doAsPrivileged" |
|
checkPermission | javax.security.auth.AuthPermission "getSubjectFromDomainCombiner" |
|
checkPermission | javax.security.auth.AuthPermission "getSubjectFromDomainCombiner" |
|
checkPermission | javax.security.auth.AuthPermission "createLoginContext.{name}" |
|
checkPermission | javax.security.auth.AuthPermission "createLoginContext.{name}" |
|
checkPermission | javax.security.auth.AuthPermission "createLoginContext.{name}" |
|
checkPermission | javax.security.auth.AuthPermission "createLoginContext.{name}" |
|
checkPermission | javax.security.auth.AuthPermission "getLoginConfiguration" |
|
checkPermission | javax.security.auth.AuthPermission "setLoginConfiguration" |
|
checkPermission | javax.security.auth.AuthPermission "refreshLoginConfiguration" |
|
checkPermission | javax.security.auth.AuthPermission "createLoginConfiguration.{type}" |
java.lang.SecurityManager Method Permission Checks
The following table shows which permissions are checked by the default implementations of the java.lang.SecurityManager methods.
Each of the specified check
methods calls the SecurityManager
checkPermission
method with the specified permission, except for the checkConnect
and checkRead
methods that take a context argument. Those methods expect the context to be an AccessControlContext
and they call the context's checkPermission
method with the specified permission.
Table 1-5 java.lang.SecurityManager Methods and Permissions
Method | Permission |
---|---|
|
|
|
|
|
|
Note: This method is deprecated; use instead public void checkPermission(Permission perm); |
|
|
|
|
|
|
|
|
|
|
if cmd is an absolute path:
else
|
|
|
|
|
|
|
Note: This method is deprecated; use instead public void checkPermission(Permission perm); |
|
|
|
Note: This method is deprecated; use instead public void checkPermission(Permission perm); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Note: This method is deprecated; use instead public void checkPermission(Permission perm); |
|
Note: This method is deprecated; use instead public void checkPermission(Permission perm); |
|
|
|
|
|
|
|
JDK Supported Permissions
The following permissions are not standard but the JDK supports them; you may need to grant them in policy files.
jdk.net.NetworkPermission "setOption.SO_FLOW_SLA";
com.sun.tools.attach.AttachPermission "attachVirtualMachine";
com.sun.jdi.JDIPermission "virtualMachineManager";
com.sun.security.jgss.InquireSecContextPermission "*";
jdk.jfr.FlightRecorderPermission "accessFlightRecorder", "registerEvent";
Default Policy Implementation and Policy File Syntax
The policy for a Java programming language application environment
(specifying which permissions are available for code from various sources, and executing as
various principals) 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).
WARNING:
The Security Manager and APIs related to it have been deprecated and are subject to removal in a future release. There is no replacement for the Security Manager. See JEP 411 for discussion and alternatives.The source location for the policy information utilized by the Policy object is up to the Policy implementation. The Policy reference implementation obtains its information from static policy configuration files.
The rest of this document pertains to the Policy reference implementation and the syntax that must be used in policy files it reads:
Default Policy Implementation
In the Policy reference implementation, the policy can be specified within one or more policy configuration files. The configuration file(s) specify what permissions are allowed for code from a specified code source, and executed by a specified principal. Each configuration file must be encoded in UTF-8.
There is by default a single system-wide policy file, and a single (optional) user policy file. By default, permissions required by JDK modules that are loaded by the platform class loader or its ancestors are always granted.
The Policy reference implementation is initialized the first time its getPermissions method is called, or whenever its refresh method is called. Initialization involves parsing the policy configuration file(s) (see Policy File Syntax), and then populating the Policy object.
Default Policy File Locations
There is by default a single system-wide policy file, and a single
(optional) user policy file. When the Policy is initialized, the system policy is loaded in
first, and then the user policy is added to it. If neither policy is present, a built-in
policy is used. This built-in policy is the same as the java.policy
file
installed with the JDK.
System Policy File Locations
By default, the system policy file is
<java-home>/conf/security/java.policy
.
The system policy file is
meant to grant system-wide code permissions. The java.policy
file
installed with the JDK allows anyone to listen on dynamic ports, and allows any code
to read certain "standard" properties that are not security-sensitive, such as the
os.name
and file.separator
properties.
User Policy File Location
By default, the user policy file is
<user-home>/.java.policy
.
Policy File Location and Format
Policy file locations are specified in the
security properties file <java-home>/conf/security/java.security
.
The policy file locations are specified as the values of properties whose names are of the following form:
policy.url.n
Here, n
is a number.
You specify each such property value in a line of the following
form:
policy.url.n=URL
Here, URL
is a URL
specification. For example, the default system and user policy files are defined in
the security properties file
as:
policy.url.1=file:${java.home}/conf/security/java.policy
policy.url.2=file:${user.home}/.java.policy
(See Property Expansion in Policy Files for information about specifying property values via a special syntax, such as
specifying the java.home
property value via ${java.home}
.)
You can actually specify a number of
URLs (including ones of the form "http://
"), and all the designated
policy files will get loaded. You can also comment out or change the second one to
disable reading the default user policy file.
The algorithm starts
at policy.url.1
, and keeps incrementing until it does not find a
URL. Thus if you have policy.url.1
and
policy.url.3
, and policy.url.3
will never be
read.
Specifying an Additional Policy File at Runtime
It is also possible to
specify an additional or a different policy file when invoking execution of an
application. This can be done via the
command line argument, which sets
the value of the -Djava.security.policy
java.security.policy
property. For
example, if you use following command, where someURL
is a URL specifying the location of a policy
file, then the specified policy file will be loaded in addition to all the policy
files that are specified in the security properties
file.
java -Djava.security.manager
-Djava.security.policy
=someURL SomeApp
The URL can be any regular URL or simply the name of a policy file in the current directory, as in:
java -Djava.security.manager -Djava.security.policy=mypolicy SomeApp
The -Djava.security.manager
option ensures that the
default security manager is installed, and thus the application is subject to policy
checks. It is not required if the application SomeApp installs a security manager.
If you use the following command (note the double equals) then just the specified policy file will be used; all the ones indicated in the security properties file will be ignored.
java -Djava.security.manager
-Djava.security.policy
==someURL SomeApp
Note:
The policy file value of the-Djava.security.policy
option is ignored if the
policy.allowSystemProperty
property in the security properties
file is set to false. The default is true.
Modifying the Policy Implementation
The Policy reference implementation can be modified by editing the security properties file, which is the java.security
file in the conf/security
directory of the JDK.
An alternative policy class can be given to replace the Policy reference implementation class, as long as the former is a subclass of the abstract Policy class and implements the getPermissions method (and other methods as necessary).
One of the types of properties you can set in java.security
is of the following form:
policy.provider=PolicyClassName
PolicyClassName must specify the fully qualified name of the desired Policy
implementation class.
The default security properties file entry for this property is the following:
policy.provider=sun.security.provider.PolicyFile
To customize, you can change the property value to specify another class, as in
policy.provider=com.mycom.MyPolicy
Policy File Syntax
The policy configuration file(s) for a JDK installation specifies what permissions (which types of system resource accesses) are granted to code from a specified code source, and executed as a specified principal.
For an applet (or an application running under a security manager) to be allowed to perform secured actions (such as reading or writing a file), the applet (or application) must be granted permission for that particular action. In the Policy reference implementation, that permission must be granted by a grant entry in a policy configuration file. The only exception is that code always automatically has permission to read files from its same (URL) location, and subdirectories of that location; it does not need explicit permission to do so.
A policy configuration file essentially contains a list of entries. It may contain a "keystore" entry, and contains zero or more "grant" entries.
Keystore Entry
A keystore is a database of private keys and their
associated digital certificates such as X.509 certificate chains authenticating the
corresponding public keys. The keytool
utility is used to create and
administer keystores. The keystore specified in a policy configuration file is used to
look up the public keys of the signers specified in the grant entries of the file. A
keystore entry must appear in a policy configuration file if any grant entries specify
signer aliases, or if any grant entries specify principal aliases.
At this time, there can be only one keystore
/keystorePasswordURL
entry in the policy file (other entries following the first one are ignored). This entry can appear anywhere outside the file's grant entries. It has the following syntax:
keystore "some_keystore_url", "keystore_type", "keystore_provider";
keystorePasswordURL "some_password_url";
Here,
- some_keystore_url
- Specifies the URL location of the keystore.
- some_password_url
- Specifies the URL location of the keystore password.
- keystore_type
- Specifies the keystore type.
- keystore_provider
- Specifies the keystore provider.
Note:
-
The input stream from
some_keystore_url
is passed to the KeyStore.load method. -
If NONE is specified as the URL, then a null stream is passed to the KeyStore.load method. NONE should be specified in the URL if the KeyStore is not file-based. For example, if it resides on a hardware token device.
-
The URL is relative to the policy file location. If the policy file is specified in the security properties file as:
policy.url.1=http://foo.example.com/fum/some.policy
and that policy file has an entry:
keystore ".keystore";
then the keystore will be loaded from:
http://foo.example.com/fum/.keystore
-
The URL can also be absolute.
A keystore type defines the storage and data format of the keystore information, and the algorithms used to protect private keys in the keystore and the integrity of the keystore itself. The default type is "PKCS12". Thus, if the keystore type is "PKCS12", it does not need to be specified in the keystore entry.
Grant Entries
Code being executed is always considered to come from a particular "code source" (represented by an object of type CodeSource
). The code source includes not only the location (URL) where the code originated from, but also a reference to the certificate(s) containing the public key(s) corresponding to the private key(s) used to sign the code. Certificates in a code source are referenced by symbolic alias names from the user's keystore. Code is also considered to be executed as a particular principal (represented by an object of type Principal
), or group of principals.
Each grant entry includes one or more "permission entries" preceded by optional codeBase
, signedBy
, and principal name/value pairs that specify which code you want to grant the permissions. The basic format of a grant entry is the following:
grant signedBy "signer_names", codeBase "URL",
principal principal_class_name "principal_name",
principal principal_class_name "principal_name",
... {
permission permission_class_name "target_name", "action",
signedBy "signer_names";
permission permission_class_name "target_name", "action",
signedBy "signer_names";
...
};
All non-italicized items must appear as-is (although case doesn't matter and some are optional). Italicized items represent variable values.
A grant entry must begin with the word grant
.
The SignedBy, Principal, and CodeBase Fields
The signedBy
, codeBase
, and principal
values are optional, and the order of these fields does not matter.
signedBy Value
A signedBy
value indicates the alias for a certificate
stored in the keystore. The public key within that certificate is used to verify the
digital signature on the code; you grant the permission(s) to code signed by the
private key corresponding to the public key in the keystore entry specified by the
alias.
The signedBy
value can be a comma-separated list of
multiple aliases. An example is "Adam,Eve,Charles", which means "signed by Adam and
Eve and Charles"; the relationship is AND, not OR. To be more exact, a statement
like "Code signed by Adam" means "Code in a class file contained in a JAR which is
signed using the private key corresponding to the public key certificate in the
keystore whose entry is aliased by Adam".
The signedBy
field is optional in that, if it is
omitted, it signifies "any signer". It doesn't matter whether the code is signed or
not or by whom.
principal Value
A principal value specifies a
class_name
/principal_name
pair which must be
present within the executing thread's principal set. The principal set is associated
with the executing code by way of a Subject.
The principal_class_name
may be set to the wildcard
value, *, which allows it to match any Principal
class. In
addition, the principal_name
may also be set to the wildcard value,
*, allowing it to match any Principal
name. When setting the
principal_class_name
or principal_name
to *,
do not surround the * with quotes. Also, if you specify a wildcard principal class,
you must also specify a wildcard principal name.
The principal field is optional in that, if it is omitted, it signifies "any principals".
Keystore Alias Replacement
If the principal class_name
/principal_name
pair is
specified as a single quoted string, then it is treated as a keystore alias. The
keystore is consulted and queried (via the alias) for an X509 Certificate. If one is
found, the principal class_name
is automatically treated as
javax.security.auth.x500.X500Principal
, and the
principal_name
is automatically treated as the subject
distinguished name from the certificate. If an X509 Certificate mapping is not
found, the entire grant entry is ignored.
codeBase Value
A codeBase
value indicates the code source location;
you grant the permission(s) to code from that location. An empty
codeBase
entry signifies "any code"; it doesn't matter where
the code originates from.
Note:
A codeBase
value is a URL and thus should always utilize slashes
(never backslashes) as the directory separator, even when the code source is
actually on a Windows system. Thus, if the source location for code on a Windows
system is actually C:\somepath\api\
, then the policy
codeBase
entry should look like:
grant codeBase "file:/C:/somepath/api/" {
...
};
The exact meaning of a codeBase
value depends on the
characters at the end. A codeBase
with a trailing
"/"
matches all class files (not JAR files) in the specified
directory. A codeBase
with a trailing "/*"
matches
all files (both class and JAR files) contained in that directory. A
codeBase
with a trailing "/-"
matches all
files (both class and JAR files) in the directory and recursively all files in
subdirectories contained in that directory. The following table illustrates the
different cases:
Table 1-6 How Codebase URLs in Downloaded Code Match Those in Policy Files
Codebase URL of Downloaded Code | Codebase URL in Policy File | Match? |
---|---|---|
www.example.com/usr/ann/ | www.example.com/usr/ann | Yes |
www.example.com/usr/ann/ | www.example.com/usr/ann/ | Yes |
www.example.com/usr/ann/ | www.example.com/usr/ann/* | Yes |
www.example.com/usr/ann/ | www.example.com/usr/ann/- | Yes |
www.example.com/usr/ann/appl.jar | www.example.com/usr/ann/ | No |
www.example.com/usr/ann/appl.jar | www.example.com/usr/ann/- | Yes |
www.example.com/usr/ann/appl.jar | www.example.com/usr/ann/* | Yes |
www.example.com/usr/ann/appl.jar | www.example.com/usr/- | Yes |
www.example.com/usr/ann/appl.jar | www.example.com/usr/* | No |
www.example.com/usr/ann/ | www.example.com/usr/- | Yes |
www.example.com/usr/ann/ | www.example.com/usr/* | No |
If you are using a modular runtime image (see the jlink
tool), you can grant permissions to the
application and library modules in the image by specifying a jrt
URL as the codeBase
value in a policy file. See JEP 220: Modular Run-Time Images for more information about
jrt
URLs.
The following example grants permission to read the foo
property to
the module com.greetings
:
grant codeBase "jrt:/com.greetings" {
permission java.util.PropertyPermission "foo", "read";
};
The Permission Entries
A permission entry must begin with the word permission
. The
word permission_class_name
in the
template in the previous section would actually be a specific permission type, such as
java.io.FilePermission
or
java.lang.RuntimePermission
.
The "action" is required for many permission types, such as java.io.FilePermission
(where it specifies what type of file access is permitted). It is not required for categories such as java.lang.RuntimePermission
where it is not necessary, you either have the permission specified by the "target_name
" value following the permission_class_name or you don't.
The signedBy
name/value pair for a permission entry is optional. If present, it indicates a signed permission. That is, the permission class itself must be signed by the given alias(es) in order for the permission to be granted. For example, suppose you have the following grant entry:
grant {
permission Foo "foobar", signedBy "FooSoft";
};
Then this permission of type Foo is granted if the Foo.class
permission was placed in a JAR file and the JAR file was signed by the private key corresponding to the public key in the certificate specified by the "FooSoft" alias, or if Foo.class
is a system class, since system classes are not subject to policy restrictions.
Items that appear in a permission entry must appear in the specified order (permission
, permission_class_name, "target_name", "action", and signedBy
"signer_names"). An entry is terminated with a semicolon.
Case is unimportant for the identifiers (permission
, signedBy
, codeBase
, etc.) but is significant for the permission_class_name or for any string that is passed in as a value.
Note:
See Appendix A: FilePermission Path Name Canonicalization Disabled By Default for important information about a change in how FilePermission path names are canonicalized.
File Path Specifications on Windows Systems
When you are specifying a java.io.FilePermission
, the "target_name" is a file path. On Windows systems, whenever you directly specify a file path in a string (but not in a codebase URL), you need to include two backslashes for each actual single backslash in the path, as in
grant {
permission java.io.FilePermission "C:\\users\\cathy\\foo.bat", "read";
};
The reason this is necessary is because the strings are processed by a tokenizer
(java.io.StreamTokenizer
), which allows "\" to be used as an escape
string (for example, "\n" to indicate a new line) and which thus requires two
backslashes to indicate a single backslash. After the tokenizer has processed the
previous file path string, converting double backslashes to single backslashes, the end
result is
"C:\users\cathy\foo.bat"
Policy File Examples
The following policy configuration file contains two entries:
// If the code is signed by "Duke", grant it read/write access to all
// files in /tmp:
grant signedBy "Duke" {
permission java.io.FilePermission "/tmp/*", "read,write";
};
// Grant everyone the following permission:
grant {
permission java.util.PropertyPermission "java.vendor", "read";
};
The following policy configuration file specifies that only code that satisfies the following conditions can call methods in the Security class to add or remove providers or to set Security Properties:
- The code was loaded from a signed JAR file that is in the "
/home/sysadmin/
" directory on the local file system. - The signature can be verified using the public key referenced by the alias name "
sysadmin
" in the keystore.
grant signedBy "sysadmin", codeBase "file:/home/sysadmin/*" {
permission java.security.SecurityPermission "Security.insertProvider.*";
permission java.security.SecurityPermission "Security.removeProvider.*";
permission java.security.SecurityPermission "Security.setProperty.*";
};
Either component of the policy entry (or both) may be missing.
The following is a policy configuration file where codeBase
is missing:
grant signedBy "sysadmin" {
permission java.security.SecurityPermission "Security.insertProvider.*";
permission java.security.SecurityPermission "Security.removeProvider.*";
};
If this policy is in effect, then code that comes in a JAR file signed by "sysadmin
" can add/remove providers, regardless of where the JAR file originated from.
The following is a policy configuration file without a signer:
grant codeBase "file:/home/sysadmin/-" {
permission java.security.SecurityPermission "Security.insertProvider.*";
permission java.security.SecurityPermission "Security.removeProvider.*";
};
In this case, code that comes from anywhere in the "home/sysadmin/"
directory on the local file system can add/remove providers. The code does not need to be signed.
The following is a policy configuration file where neither codeBase
nor signedBy
is included:
grant {
permission java.security.SecurityPermission "Security.insertProvider.*";
permission java.security.SecurityPermission "Security.removeProvider.*";
};
Here, with both code source components missing, any code (regardless of where it originated from, or whether or not it is signed, or who signed it) can add/remove providers.
The following represents a principal-based entry:
grant principal javax.security.auth.x500.X500Principal "cn=Alice" {
permission java.io.FilePermission "/home/Alice", "read, write";
};
This permits any code executing as the X500Principal, "cn=Alice
", permission to read and write to "/home/Alice
”.
The following represents a principal-based entry with a wildcard value:
grant principal javax.security.auth.x500.X500Principal * {
permission java.io.FilePermission "/tmp", "read, write";
};
This permits any code executing as an X500Principal (regardless of the distinguished name), permission to read and write to "/tmp
”.
The following example shows a grant statement with both codesource and principal information:
grant codebase "http://www.games.example.com",
signedBy "Duke",
principal javax.security.auth.x500.X500Principal "cn=Alice" {
permission java.io.FilePermission "/tmp/games", "read, write";
};
This allows code downloaded from "www.games.example.com
", signed by "Duke
", and executed by "cn=Alice
", permission to read and write into the "/tmp/games
" directory.
The following example shows a grant statement with KeyStore alias replacement:
keystore "http://foo.example.com/blah/.keystore";
grant principal "alice" {
permission java.io.FilePermission "/tmp/games", "read, write";
};
"alice
" will be replaced by the following:
javax.security.auth.x500.X500Principal "cn=Alice"
This assumes that X.509 certificate associated with the keystore alias, alice
, has a subject distinguished name of "cn=Alice
". This allows code executed by the X500Principal "cn=Alice
" permission to read and write into the "/tmp/games
" directory.
Property Expansion in Policy Files
Property expansion is possible in policy files and in the security properties file.
Property expansion is similar to expanding variables in a shell. That is, when a string like
${some.property}
appears in a policy file, or in the security properties file, it will be expanded to the value of the system property. For example,
permission java.io.FilePermission "${user.home}", "read";
will expand "${user.home}
" to use the value of the
"user.home" system property. If that property's value is
"/home/cathy
", then the previous example is equivalent to
permission java.io.FilePermission "/home/cathy", "read";
In order to assist in platform-independent policy files, you can also
use the special notation of "${/}
", which is a shortcut for
${file.separator}
". This allows things like
permission java.io.FilePermission "${user.home}${/}*", "read";
If the value of the "user.home
" property is
/home/cathy
, and you are on Linux or macOS, the previous
example gets converted to:
permission java.io.FilePermission "/home/cathy/*", "read";
If on the other hand the "user.home
" value is
C:\users\cathy
and you are on a Windows system, the previous
example gets converted to:
permission java.io.FilePermission "C:\users\cathy\*", "read";
Also, as a special case, if you expand a property in a codebase, such as
grant codeBase "file:${my.libraries}/api/"
then any file separator characters will be automatically converted to
/
characters. For example, suppose the value of
my.libraries
is C:\Users\me\lib
. Thus on a
Windows system, the previous example would get converted to
grant codeBase "file:C:/Users/me/lib/api/"
Thus you don't need to use ${/}
in codebase strings
(and you shouldn't). Property expansion takes place anywhere a double quoted string
is allowed in the policy file. This includes the "signer_names", "URL", "target_name", and "action"
fields. Whether or not property expansion is allowed is controlled by the value of
the "policy.expandProperties
" property in the security properties
file. If the value of this property is true (the default), expansion is allowed.
Note:
You can't use nested properties; they will not work. For example,
"${user.${foo}}"
doesn't work, even if the "foo
" property is set to
"home
". The reason is the property parser doesn't recognize
nested properties; it simply looks for the first "${
", and then
keeps looking until it finds the first "}
" and tries to
interpret the result (in this case, "${user.$foo}
") as a
property, but fails if there is no such property.
Note:
If a property can't be expanded in a grant entry, permission entry,
or keystore entry, that entry is ignored. For example, if the system property
"foo
" is not defined and you have:
grant codeBase "${foo}" {
permission ...;
permission ...;
};
then all the permissions in this grant entry are ignored. If you have
grant {
permission Foo "${foo}";
permission Bar "barTarget";
};
then only the "permission Foo...
" entry is ignored.
And finally, if you have
keystore "${foo}";
then the keystore entry is ignored.
Windows Systems, File Paths, and Property Expansion
The file path specifications on Windows systems should include two backslashes for each actual single backslash.
As mentioned in File Path Specifications on Windows Systems, on Windows systems, when you directly specify a file path in a string (but not in a codebase URL), you need to include two backslashes for each actual single backslash in the path, as in
grant {
permission java.io.FilePermission "C:\\users\\cathy\\foo.bat", "read";
};
This is because the strings are processed by a tokenizer
(java.io.StreamTokenizer
), which allows "\
" to
be used as an escape string (e.g., "\n
" to indicate a new line) and
which thus requires two backslashes to indicate a single backslash. After the
tokenizer has processed the previous file path string, converting double backslashes
to single backslashes, the end result is
"C:\users\cathy\foo.bat"
Expansion of a property in a string takes place after the tokenizer has processed the string. Thus if you have the string
"${user.home}\\foo.bat"
then first the tokenizer processes the string, converting the double backslashes to a single backslash, and the result is
"${user.home}\foo.bat"
Then
the ${user.home}
property is expanded and the end result is
"C:\users\cathy\foo.bat"
assuming
the "user.home
" value is C:\users\cathy
. Of course,
for platform independence, it would be better if the string was initially specified
without any explicit slashes, i.e., using the ${/}
property instead, as
in
"${user.home}${/}foo.bat"
General Expansion in Policy Files
Generalized forms of expansion are also supported in policy files. For example, permission names may contain a string of the following form:
${{protocol:protocol_data}}
If such a string occurs in a permission name, then the value in protocol determines the exact type of expansion that should occur, and protocol_data is used to help perform the expansion. protocol_data may be empty, in which case the previous string should simply take the form:
${{protocol}}
There are two protocols supported in the default policy file implementation:
-
${{self}}
The protocol,
self
, denotes a replacement of the entire string,${{self}}
, with one or more principal class/name pairs. The exact replacement performed depends upon the contents of the grant clause to which the permission belongs.If the grant clause does not contain any principal information, the permission will be ignored (permissions containing
${{self}}
in their target names are only valid in the context of a principal-based grant clause). For example,BarPermission
will always be ignored in the following grant clause:grant codebase "www.example.com", signedby "duke" { permission BarPermission "... ${{self}} ..."; };
If the grant clause contains principal information,
${{self}}
will be replaced with that same principal information. For example,${{self}}
inBarPermission
will be replaced withjavax.security.auth.x500.X500Principal "cn=Duke"
in the following grant clause:grant principal javax.security.auth.x500.X500Principal "cn=Duke" { permission BarPermission "... ${{self}} ..."; };
If there is a comma-separated list of principals in the grant clause, then
${{self}}
will be replaced by the same comma-separated list or principals. In the case where both the principal class and name are wildcarded in the grant clause,${{self}}
is replaced with all the principals associated with theSubject
in the currentAccessControlContext
.The following example describes a scenario involving both
self
and Keystore Alias Replacement together:keystore "http://foo.example.com/blah/.keystore"; grant principal "duke" { permission BarPermission "... ${{self}} ..."; };
In the previous example, "
duke
" will first be expanded intojavax.security.auth.x500.X500Principal "cn=Duke"
assuming the X.509 certificate associated with theKeyStore
alias, "duke
", has a subject distinguished name of "cn=Duke
". Next,${{self}}
will be replaced with the same principal information that was just expanded in the grant clause:javax.security.auth.x500.X500Principal "cn=Duke"
. -
${{alias:alias_name}}
The protocol,
alias
, denotes a java.security.KeyStore alias substitution. TheKeyStore
used is the one specified in the Keystore Entry. alias_name represents an alias into theKeyStore
.${{alias:alias_name}}
is replaced withjavax.security.auth.x500.X500Principal "DN"
, where DN represents the subject distinguished name of the certificate belonging to alias_name. For example:keystore "http://foo.example.com/blah/.keystore"; grant codebase "www.example.com" { permission BarPermission "... ${{alias:duke}} ..."; };
In the previous example the X.509 certificate associated with the alias, duke, is retrieved from the
KeyStore
, foo.example.com/blah/.keystore. Assuming duke's certificate specifies "o=dukeOrg, cn=duke
" as the subject distinguished name, then${{alias:duke}}
is replaced withjavax.security.auth.x500.X500Principal "o=dukeOrg, cn=duke"
.The permission entry is ignored under the following error conditions:
- The keystore entry is unspecified
- The alias_name is not provided
- The certificate for alias_name can not be retrieved
- The certificate retrieved is not an X.509 certificate
Appendix A: FilePermission Path Name Canonicalization Disabled By Default
A canonical path is a path that doesn't contain any links or shortcuts. Performing path name canonicalization in a FilePermission
object can negatively affect performance.
Before JDK 9, path names were canonicalized when two FilePermission
objects were compared. This allowed a program to access a file using a different name than the name that was granted to a FilePermission
object in a policy file, as long as the object pointed to the same file. Because the canonicalization had to access the underlying file system, it could be quite slow.
In JDK 9, path name canonicalization is disabled by default. This means two FilePermission
objects aren’t equal to each other if one uses an absolute path and the other uses a relative path, or one uses a symbolic link and the other uses a target, or one uses a Windows long name and the other uses a DOS-style 8.3 name. This is true even if they all point to the same file in the file system.
Therefore, if a path name is granted to a FilePermission
object in a policy file, then the program should also access that file using the same path name style. For example, if the path name in the policy file is using a symbolic link, then the program should also use that symbolic link. Accessing the file with the target path name will fail the permission check.
Compatibility Layer
A compatibility layer has been added to ensure that granting a FilePermission
object for a relative path will permit applications to access the file with an absolute path (and conversely). This works for the default Policy provider and the Limited doPrivileged calls.
For example, a FilePermission
object on a file with a relative path name of "a"
no longer implies a FilePermission
object on the same file with an absolute path name as "/pwd/a"
("pwd"
is the current working directory). Granting code a FilePermission
object to read "a"
allows that code to also read "/pwd/a"
when a Security Manager is enabled.
The compatibility layer doesn’t cover translations between symbolic links and targets, or Windows long names and DOS-style 8.3 names, or any other different name forms that can be canonicalized to the same name.
Customizing Path Name Canonicalization
The system properties in Table 1-7 can be used to customize theFilePermission
path name canonicalization. See How to Specify a java.lang.System Property.
Table 1-7 System Properties to Customize Path Name Canonicalization
System Property | Default Value | Description |
---|---|---|
jdk.io.permissionsUseCanonicalPath |
false |
The system property can be used to enable or disable path name canonicalization in the
|
jdk.security.filePermCompat |
false |
The system property can be used to extend the compatibility layer to support third-party Policy implementations.
|