JDK-8319333 : Security properties files inclusion
  • Type: CSR
  • Component: security-libs
  • Sub-Component: java.security
  • Priority: P3
  • Status: Closed
  • Resolution: Approved
  • Fix Versions: 24
  • Submitted: 2023-11-02
  • Updated: 2024-09-21
  • Resolved: 2024-09-21
Related Reports
CSR :  
Description
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/
```

Comments
Thanks all for the additional review work; moving to Approved.
21-09-2024

Moving this CSR to Finalized as indicated by [~mullan] (see [here][1]) and considering that [~weijun] had no other comments (see [here][2]). [1]: https://github.com/openjdk/jdk/pull/16483#issuecomment-2332563047 [2]: https://github.com/openjdk/jdk/pull/16483#issuecomment-2354349948
17-09-2024

Description updated to reflect that changes to the Java SE specification are required as part of this change.
28-08-2024

The scope should be now "SE" and the Interface should include Java API since there is an API change to throw IAE. Please also remove or update this sentence: "Changes to the Java SE specification are not required as part of this change."
27-08-2024

I made a couple of modifications to reflect in the CSR what has been discussed in the PR and updated in the proposed code change: 1) Added a "Security::getProperty and Security::setProperty APIs" subsection. An `IllegalArgumentException` exception is now thrown if programmatically getting or setting a Security property with the name "include". The user guide has been updated as well. 2) Aligned the java.security documentation to the code by removing the "this file" part (minor change that does not affect the meaning).
07-08-2024

[~mullan], acknowledged; thanks.
12-07-2024

[~darcy] We have completed a security review of this feature and sent our feedback to Martin and Francisco. No significant issues were found and the Enhancement can proceed.
12-07-2024

A user guide documentation has been written in [JDK-8336162]
11-07-2024

[~mbalao] [~fferrari] We want to take a closer look at the security impact of this Enhancement before proceeding. We will let you know if we find any issues or if it is ok to proceed.
08-05-2024

[~darcy]: This enhancement relies on the existing `java.util.Properties` grammar, described for the [::load(Reader) API][1] and used for the _java.security_ properties file. As for the new `include` property value, its grammar is the same as for the [`java.nio.file.Path::of(String,...)` API][2], after property expansion. This enhancement combines these existing blocks and assigns the semantics described in the proposal. Can you please elaborate more on the type of grammar formalization that you find beneficial? Would adding these references to the proposal be sufficient? Thanks.- [1]: https://docs.oracle.com/en/java/javase/22/docs/api///java.base/java/util/Properties.html#load%28java.io.Reader%29 [2]: https://docs.oracle.com/en/java/javase/22/docs/api///java.base/java/nio/file/Path.html#of%28java.lang.String,java.lang.String...%29
06-05-2024

[~darcy]: regarding cycle detection, it is performed in [Security.java:255-265](https://github.com/openjdk/jdk/blob/6c73962c98cc11405573711d55375136e775daa4/src/java.base/share/classes/java/security/Security.java#L255-L265). For regular files, it is based on the result of [Path::toRealPath](https://docs.oracle.com/en/java/javase/22/docs/api/java.base/java/nio/file/Path.html#toRealPath(java.nio.file.LinkOption...)) with default options, where symbolic links are resolved to their final target. Directories are explicitly rejected and nonexistent files fail when doing `Files.newInputStream(path)`. Finally, non-regular existing files (such as _Linux_ named pipes or `/proc/<PID>/dev/fd` pseudo-file system files) are detected based on the result of [Path::toAbsolutePath](https://docs.oracle.com/en/java/javase/22/docs/api/java.base/java/nio/file/Path.html#toAbsolutePath()), since [Path::toRealPath](https://docs.oracle.com/en/java/javase/22/docs/api/java.base/java/nio/file/Path.html#toRealPath(java.nio.file.LinkOption...)) fails on them. This is for uncommon, still convenient use cases such as the ones described in [90df17c](https://github.com/openjdk/jdk/commit/90df17c2781a47920dbeaa981888ddff65bfe8ad). Even if we use hard-links, let's suppose a case in which we see the same file with several different names. If there is a cyclic include, one of the names will soon repeat and be detected.
06-05-2024

PS And I think the proposal would benefit from providing a more formal grammar for the include mechanism.
06-05-2024

Moving to Provisional, not Approved. I'm a bit uneasy with this proposal; the ability to do recursive including, while clearly useful, also seems to me to open up a large area of problems to detect or prevent. For example, is the cycle detection based on the names of the file or their identity on the file system (i.e. what about symlinks?)
06-05-2024

Based on the last comment made by [~mullan], I'll move this CSR to the Proposed state and target JDK 23.
03-05-2024

[~darcy] I have reviewed the CSR and I am satisfied with this Enhancement. I think it will make it easier for users to use different security configurations based on application requirements or security profiles. [~weijun] has also done an extensive code review.
03-05-2024

[~fferrari] [~mbalao] Can you please change the priority of the CSR and Issue to P3 -- I think this Enhancement is significant enough that the priority should be higher than P4.
03-05-2024

Moving back to Draft. [~alanb] and [~mullan], please review this request. [~fferrari], I think more consensus is needed on this approach before the CSR review can proceed.
02-11-2023