Summary
-------
In connection with [JEP 411](https://openjdk.java.net/jeps/411), provide clear warnings when a Security Manager is enabled at startup or installed at run time. If a command line option prevents a Security Manager from being installed at run time, provide a clear message in the `UnsupportedOperationException` thrown by `System::setSecurityManager`.
Problem
-------
The current warning when a Security Manager is enabled at startup or installed at run time is:
```
WARNING: The Security Manager is deprecated and will be removed in a future release.
```
The current message in the `UnsupportedOperationException` thrown by `System::setSecurityManager` when `-Djava.security.manager=disallow` occurs on the command line is:
```
Runtime configured to disallow security manager
```
Both statements are true, but they provide no context for anyone seeing them. The message when a Security Manager is installed at run time is especially inadequate, since the person who sees it is unlikely to be the author of the code that attempted to install a Security Manager. The message also sows confusion over whether the installation succeeded.
We can improve these warnings to contain more details and to better assist people (such as support engineers) who see them in a production environment.
Solution
--------
When the Security Manager is enabled on the command line, we will enhance the warning to indicate that a command line option was involved in enabling the Security Manager, and that the Security Manager will be removed in a future release.
When the Security Manager is installed at run time, we will enhance the warning to show which class called `System::setSecurityManager`. This warning is analogous to the _illegal reflective-access warning_ introduced in Java 9 to show when a class uses reflection to call a method that is otherwise inaccessible. (Illegal reflective-access warnings are described in [JEP 261](https://openjdk.java.net/jeps/261#Relaxed-strong-encapsulation). They appeared in Java 9 through Java 16. Java 17 no longer gives such warnings because it disallows the use of reflection that caused them, as described in [JEP 403](https://openjdk.java.net/jeps/403).)
When a Security Manager is disallowed at run time via `-Djava.security.manager=disallow` on the command line, but a program attempts to install a Security Manager at run time via `System::setSecurityManager`, we will change the detail message of the exception thrown by `System::setSecurityManager` to indicate that the Security Manager is deprecated and will be removed in a future release.
Specification
-------------
(1) If the default Security Manager or a custom Security Manager is enabled at startup:
```
java -Djava.security.manager MyApp
java -Djava.security.manager="" MyApp
java -Djava.security.manager=default MyApp
java -Djava.security.manager=com.foo.bar.Server MyApp
```
then the following warning is issued at startup:
```
WARNING: A command line option has enabled the Security Manager
WARNING: The Security Manager is deprecated and will be removed in a future release
```
(The four invocations of `java -D...` shown above set the system property `java.security.manager` to, respectively, the empty string, the empty string, the string `default`, and the class name of a custom Security Manager. These invocations were the supported ways of enabling a Security Manager at startup in Java releases prior to Java 12. Java 12 added support for the strings `allow` and `disallow`, shown next.)
(2) If a Security Manager is not enabled at startup, but could be installed dynamically during run time:
```
java MyApp
java -Djava.security.manager=allow MyApp
```
then no warning is issued at startup. Instead, a warning is issued at run time when `System::setSecurityManager` is invoked, as follows:
```
WARNING: A terminally deprecated method in java.lang.System has been called
WARNING: System::setSecurityManager has been called by com.foo.bar.Server (file:/tmp/foobarserver/thing.jar)
WARNING: Please consider reporting this to the maintainers of com.foo.bar.Server
WARNING: System::setSecurityManager will be removed in a future release
```
(The second line adopts the approach of the illegal reflective-access warning by loudly identifying the caller's class name and code source (i.e., JAR-file path). It is understood that this will likely cause the second line to wrap.)
(3) If a Security Manager is not enabled at startup, and the system property `java.security.manager` is set to `disallow`:
```
java -Djava.security.manager=disallow MyApp
```
then no warning is issued at startup, nor at run time if an attempt is made to install a Security Manager dynamically by invoking `System::setSecurityManager`. However, every invocation of `System::setSecurityManager` will throw an `UnsupportedOperationException` with the following detail message:
```
The Security Manager is deprecated and will be removed in a future release
```