Summary
-------
Extend security properties capabilities so files containing properties definitions can include other files inline. When a file is included, all its security properties are added as if defined at that point.
Problem
-------
Multiple JDKs deployed on a system (i.e. different JDK releases) often require common values for security properties. At the moment, it is not possible to define and manage these values in a centralized way. As a result, values need to be defined in each JDK `java.security` file separately, leading to duplication and possible misconfiguration. This problem aggravates when switching between sets of properties that constitute security profiles. The existing `java.security.properties` mechanism (system property) has drawbacks when used as a workaround to this problem, as the configuration needs to be passed for each JVM execution.
Solution
--------
Introduce a special security property named _include_ which takes a filesystem path as value. Each definition of this property has the effect of including all properties from the referred file in place. With this solution, each JDK `java.security` file can include a centralized repository of security properties. Security properties in the centralized repository may be organized per security profile, library component, JDK release, a combination of the previous or any other criteria.
To provide more flexibility, filesystem paths assigned to the new include security property may contain one or multiple placeholders that get expanded to system property values in run time. If the system property referred by the placeholder is not available (i.e. its value is `null`), expansion is to the empty string. This behavior makes it possible to parameterize part of the security configuration and switch between a global security profile (default) and alternative profiles on a per-run basis. Notice that this is possible because system properties can be passed as Java launcher arguments. In addition to limiting the scope of a security profile to a single execution, non-privileged users —who are not allowed to modify the _java.security_ file— may benefit from applying a profile that meets their needs. See more about this configuration in subsections _Syntax_ and _Examples_ of _Specification_.
Specification
-------------
Changes to the Java SE specification are required in the Security::getProperty and Security::setProperty APIs as described in this section. In addition, the _include_ security property is assigned special semantics. By default, OpenJDK's `java.security` file does not include any other file.
### Syntax
The special _include_ property can be defined one or multiple times in a security properties file with a filesystem path value. The effect of each definition is to include a referred security properties file inline, adding all its properties. Included files, as well as files pointed by `java.security.properties`, can include other files recursively. Paths may be absolute or relative, and may contain system properties for expansion in the form of `${system.property}`. If a system property does not have a value, it expands to the empty string. Each relative path is resolved against the base file containing its _include_ definition, if local. An error will be thrown if a file cannot be included, either because it does not exist, cannot be resolved, or is recursively included more than once.
### java.security
The following paragraphs are proposed for the `java.security` file:
```
The special "include" property can be defined one or multiple times with
a filesystem path value. The effect of each definition is to include a
referred security properties file inline, adding all its properties.
Security properties defined before an include statement may be overridden
by properties in the included file, if their names match. Conversely,
properties defined after an include statement may override properties in
the included file.
Included files, as well as files pointed to by java.security.properties,
can include other files recursively. Paths may be absolute or relative.
Each relative path is resolved against the base file containing its
"include" definition, if local. Paths may contain system properties for
expansion in the form of ${system.property}. If a system property does
not have a value, it expands to the empty string.
An error will be thrown if a file cannot be included. This may happen
if the file cannot be resolved, does not exist, is a directory, there are
insufficient permissions to read it, it is recursively included more than
once, or for any other reason. For a secure JDK configuration, it is
important to review OS write permissions assigned to any file included.
Examples:
1) include ${java.home}/conf/security/extra.security
2) include extra.security
3) include ${java.home}/conf/security/profile${SecurityProfile}.security
```
### Security::getProperty and Security::setProperty APIs
`include` is a reserved word not available to define a security property. Any call to `java.security.Security.getProperty("include")` or `java.security.Security.setProperty("include", ...)` throws an unchecked `IllegalArgumentException` exception. The following is proposed to document this change:
```
/**
* Gets a security property value.
*
* <p>First, if there is a security manager, its
* {@code checkPermission} method is called with a
* {@code java.security.SecurityPermission("getProperty."+key)}
* permission to see if it's ok to retrieve the specified
* security property value.
*
* @param key the key of the property being retrieved.
*
* @return the value of the security property, or {@code null} if there
* is no property with that key.
*
* @throws SecurityException
* if a security manager exists and its {@link
* java.lang.SecurityManager#checkPermission} method
* denies
* access to retrieve the specified security property value
* @throws NullPointerException if key is {@code null}
* @throws IllegalArgumentException if key is reserved and cannot be
* used as a Security property name. Reserved keys are:
* "include".
*
* @see #setProperty
* @see java.security.SecurityPermission
*/
public static String getProperty(String key) {
...
}
```
```
/**
* Sets a security property value.
*
* <p>First, if there is a security manager, its
* {@code checkPermission} method is called with a
* {@code java.security.SecurityPermission("setProperty."+key)}
* permission to see if it's ok to set the specified
* security property value.
*
* @param key the name of the property to be set.
*
* @param datum the value of the property to be set.
*
* @throws SecurityException
* if a security manager exists and its {@link
* java.lang.SecurityManager#checkPermission} method
* denies access to set the specified security property value
* @throws NullPointerException if key or datum is {@code null}
* @throws IllegalArgumentException if key is reserved and cannot be
* used as a Security property name. Reserved keys are:
* "include".
*
* @see #getProperty
* @see java.security.SecurityPermission
*/
public static void setProperty(String key, String datum) {
...
}
```
### Examples (valid)
Relative path (multi-platform):
```
include extra.security
```
Absolute path using an expanded system property (multi-platform):
```
include ${java.home}/conf/security/extra.security
```
Absolute path (Linux):
```
include /etc/crypto-policies/back-ends/java.config
```
Absolute path, back-slashes (Windows):
```
include C:\\Program Files\\Common Files\\OpenJDK\\java.config
```
Absolute path, forward-slashes (Windows):
```
include C:/Program Files/Common Files/OpenJDK/java.config
```
UNC path (Windows):
```
include \\\\WindowsHost\\Share\\java.config
```
Switch between profiles via a system property (Linux):
```
include ${java.home}/conf/security/profile${SecurityProfile}.security
```
In this case, the file _profile.security_ must exist and may define a default security profile or be empty. Other files such as _FIPS.security_ may define alternative profiles. To apply an alternative profile, the JVM may be launched with the `-DSecurityProfile=FIPS` argument. System administrators and packagers have flexibility to establish profile strategies, as the proposed specification does not prescribe system properties names or values.
### Examples (invalid)
URLs are not allowed:
```
include file:///etc/crypto-policies/back-ends/java.config
```
Included files must exist:
```
include non-existent-file.security
```
Directories cannot be included:
```
include /etc/crypto-policies/back-ends/
```