Summary
-------
The implementation of the Security Manager will be removed from the JDK. It will no longer be possible for the Security Manager to be enabled, either at startup or while an application is running. The behavior of most Security Manager related classes and methods will be degraded, but they will not be removed. We plan to remove the APIs in a future release.
Problem
-------
The Security Manager was deprecated for removal in JDK 17 ([JEP 411](https://openjdk.org/jeps/411)). This included terminally deprecating the Security Manager APIs and warning users if their Java applications relied on the Security Manager. These actions were designed to prepare users and developers for the removal of the Security Manager in a future version of Java.
We now propose to remove the Security Manager functionality as described in the summary and solution sections.
Solution
--------
- Remove the ability to enable the Security Manager at startup.
- Prevent a custom Security Manager from being installed during run time.
- Render the Security Manager API non-functional, in expectation of removing the API in a future release.
The vast majority of applications do not require the Security Manager, do not recommend the Security Manager, do not enable the Security Manager themselves, and do not work if other code enables the Security Manager. A small number of applications that need to enable the Security Manager will need to transition to alternative security mechanisms.
Specification
-------------
The complete set of API changes are in the attached apidiff. Here is a summary of the API changes, including changes to non-APIs such as system properties and other changes that are not surfaced in API specifications.
### Changes in `java.lang`
- `java.lang.SecurityManager`
- All of the `check*` methods are changed to always throw `SecurityException`.
- `getSecurityContext` used to return a snapshot of the current calling context, which included the current thread's access control context and any limited privilege scope. It now returns an `AccessControlContext` as described by `AccessController::getContext` below.
- The specification of the `java.security.manager` system property has been removed from the class description as it is no longer supported. See the Command Line changes section for more details.
- `java.lang.System`
- `setSecurityManager` used to set the system-wide Security Manager. It now always throws `UnsupportedOperationException`. That is, it is possible to instantiate a `java.lang.SecurityManager` but not possible to install it system-wide.
- `getSecurityManager` used to return the system-wide Security Manager. It now always returns `null`.
- `java.lang.ClassLoader`
- The default domain assigned to classes by the `defineClass((String, byte[], int, int)` method is the same as before but is not granted any permissions (i.e. the `ProtectionDomain::getPermissions` method always returns `null`).
### Changes in `java.security`
The core Security Manager APIs live in the `java.security` package. Most classes in this package are concerned with cryptography, and do not change in JDK 24. The classes that change are as follows.
- `java.security.AccessController`
- Details about the algorithms that were used by the `checkPermission` method to determine whether access should be granted or denied have been removed from the class description as they no longer apply.
- `doPrivileged` (6 variants) and `doPrivilegedWithCombiner` (4 variants) used to perform the specified `PrivilegedAction` or `PrivilegedExceptionAction` with privileges enabled. These methods now execute the action immediately. This is consistent with the prior behavior of these methods if a Security Manager is not enabled.
- `checkPermission` always throws `AccessControlException`.
- `getContext` used to return a snapshot of the current calling context, which included the current thread's access control context and any limited privilege scope. It now returns an `AccessControlContext` that grants no permissions:
- `checkPermission` throws `AccessControlException`.
- `getDomainCombiner` returns `null`.
- `java.security.AccessControlContext`
- `checkPermission` always throws `SecurityException`.
- `java.security.DomainCombiner`: Details about how the `DomainCombiner` is used in access control operations and decisions has been removed from the class description since it no longer applies.
- `java.security.Permission`
- `checkGuard` always throws `SecurityException`.
- `java.security.ProtectionDomain`
- The class refers to "the current policy" in several places. To clarify what the current policy means, an API Note has been added to the class description and several methods to state that: "Installing a system-wide `Policy` object is no longer supported. The current policy is always a `Policy` object that grants no permissions."
- The text "when being executed on behalf of a given set of Principals" has been removed from the class description as that refers to Security Manager behavior that is no longer supported.
- The text referring to methods being called when permissions are checked has been removed from several methods as that depends on Security Manager behavior which has been removed.
- The dynamic (non-static) permissions are always empty since `Policy::getPolicy` always returns a `Policy` object containing no permissions.
- `java.security.Policy`
- Details about how the Java runtime calls the `implies` method of the system-wide `Policy` object for access control decisions has been removed from the class description since it no longer applies.
- `setPolicy` used to install the system-wide `Policy` object. It now always throws `UnsupportedOperationException`. That is, it is possible to instantiate a `Policy` but not possible to install it system-wide.
- `getPolicy` used to return the system-wide `Policy` object. It now returns a `Policy` object that grants no permissions:
- `getParameters` returns `null`.
- `getPermissions(CodeSource)` and `getPermissions(ProtectionDomain)` return a read-only empty `PermissionCollection`.
- `implies` returns `false`.
- The `SUN` security provider no longer supports the "JavaPolicy" `Policy` type and the implementation has been completely removed. The removal of this implementation also has the following impact:
- the `${java.home}/conf/security/java.policy` and `${user.home}/.java.policy` files are not supported. These were the default system-wide and user-specific policy files supported by the implementation. The system-wide policy file has been removed from the JDK.
- the `${java.home}/lib/security/default.policy` file also has been removed. This was an implementation specific file that contained the permissions granted to each JDK module and is no longer necessary.
- the `policy.provider`, `policy.url.n`, and `policy.ignoreIdentityScope` security properties have been removed and are no longer supported (also mentioned below in the System and Security Properties section).
- `java.security.SecureClassLoader`: the class description has been modified to no longer state that permissions are retrieved by the system policy by default.
### Changes in `javax.security`
The `javax.security.auth` package defines the Java Authentication and Authorization Service (JAAS) API. This API is unrelated to the Security Manager API but some of its method signatures use deprecated classes from the Security Manager API. Those methods were deprecated in JDK 18 ([JDK-8267108](https://bugs.openjdk.org/browse/JDK-8267108)) and are discussed below.
- `javax.security.auth.Subject`
- `getSubject` always throws `UnsupportedOperationException`. This is stricter than in JDK 23, where `getSubject` only threw `UnsupportedOperationException` if a Security Manager is not allowed (per command line options); see [JDK-8328643](https://bugs.openjdk.org/browse/JDK-8328643) for more details.
- `doAs` (2 variants) and `doAsPrivileged` (2 variants) launch the action and bind the subject to the period of execution.
- the `callAs` and `current` methods previously behaved differently in JDK 23 when a Security Manager was allowed. This behavior no longer applies and has been removed from the specification.
- `javax.security.auth.SubjectDomainCombiner`: The class description has been modified to state that it is no longer used in access control operations and decisions.
### Changes in `java.rmi`
- All of the changes to `java.lang.SecurityManager` also apply to the `java.rmi.RMISecurityManager` subclass.
- `java.rmi.server.RMIClassLoader::getSecurityContext` always returns `null`.
- The Remote Code Downloading mechanism has been removed (see below).
- The `rmiregistry` tool now no longer uses a Security Manager.
The Remote Code Downloading mechanism has been removed. The `java.rmi.server.RMIClassLoader` class has a service provider interface (SPI) that can be configured via a system property. The default SPI implementation is described in `RMIClassLoader::getDefaultProviderInstance`. The default provider previously supported a feature called *Remote Code Downloading* which allowed an RMI client to load classes from a codebase specified by an RMI server, and vice-versa. Remote Code Downloading was enabled only when a Security Manager was enabled. With the removal of the Security Manager, the Remote Code Downloading mechanism has also been removed. As a workaround, ambitious users of RMI can perform class loading from the codebase in their own SPI implementation.
### System and security properties
- Support for the following system properties is removed: `java.security.policy`, `jdk.security.filePermCompat`, `sun.security.policy.utf8`, `sun.security.policy.numcaches`, and `sun.net.maxDatagramSockets`.
- The "access" and "policy" options of the `java.security.debug` system property no longer apply and are removed.
- Support for the following security properties is removed: `policy.provider`, `policy.url.n`, `policy.ignoreIdentityScope`, `package.access`, and `package.definition`.
- The specification of the `networkaddress.cache.ttl` security property has been modified. The text that states that the value is set to forever when a Security Manager is set has been removed. If the property is not set, the default behavior is the same as when a Security Manager was not enabled -- to cache for 30 seconds.
### Specification changes across the Java Platform API
- Historically, approximately 1,000 methods and constructors were specified to throw a `SecurityException` if a Security Manager was enabled and appropriate permissions were not granted. All such constructors and methods are respecified to not throw `SecurityException` and remove any text about the Security Manager. They will operate as they did in JDK 23 with no Security Manager enabled.
- Some methods are still specified to throw a `SecurityException` because they may be the result of security checks that are performed instead of, or in addition to those of the Security Manager. These methods have either been left unchanged, or in some cases the specification for the `@throws SecurityException` has been modified to remove text about Security Manager specific permission checks. Examples include:
- The `JMXAuthenticator::authenticate` and `JMXConnectorFactory::connect` methods in the `javax.managerment.remote` package.
- The `getPixelColor`, `createScreenCapture`, and `createMultiResolutionScreenCapture` methods of `java.awt.Robot`.
- All methods of `javax.management.remote.rmi.RMIConnection` that throw `SecurityException`.
- The class description of `javax.management.MBeanServer` has been modified to state that methods of `MBeanServer` and its subclasses may throw `SecurityException` if the implementation doesn't authorize access to the underlying resource.
- A number of methods were specified to "filter" or "sanitize" their return value, rather than throw `SecurityException`, when denied by the Security Manager:
- The `getResourceStream` method of `java.lang.Class`
- The `findResource`, `findResources`, `getResource`, `getResourceAsStream`, `getResources`, `getSystemResource`, `getSystemResourceAsStream`, `getSystemResources`, and `resources` method of `java.lang.ClassLoader`
- The `getResourceAsStream` method of `java.lang.Module`
- The `getLocalAddress` and `receive` methods of `java.net.DatagramSocket`
- The `getCanonicalHostName`, `getHostName`, and `getLocalHost` methods of `java.net.InetAddress`
- The `getHardwareAddress`, `getInetAddresses`, `getInterfaceAddresses`, and `inetAddresses` methods of `java.net.NetworkInterfaces`
- The `getInetAddress`, `getLocalSocketAddress`, and `toString` methods of `java.net.ServerSocket`
- The `getLocalAddress` and `getLocalSocketAddress` methods of `java.net.Socket`
- The `getFileStores` and `getRootDirectories` methods of `java.nio.file.FileSystem`.
- The `getLocalAddress` method of `AsynchronousChannel`, `AsynchronousServerChannel`, `SocketChannel` and `ServerSocketChannel` in the `java.nio` package.
- The `getLocalAddress` and `receive` methods of `java.nio.channels.DatagramChannel`.
The specification of these methods is updated to remove all mention of this filtering. There is no behavior change for code that runs without a SecurityManager.
- Three methods are respecified to always be no-ops: `java.lang.Thread::checkAccess`, `java.lang.ThreadGroup::checkAccess`, and `java.util.logging.LogManager::checkAccess`. These methods originally checked if the current thread had permission to modify the thread, thread group, or logging configuration, and only if a Security Manager was enabled, otherwise they returned normally and were no-ops. Since the Security Manager is no longer supported, it makes sense to change these to be always no-ops.
- The standard permission target names of several subclasses of `java.security.Permission` (`java.awt.AWTPermission`, `java.io.SerializablePermission`, `java.lang.RuntimePermission`, `java.lang.reflect.ReflectPermission`, `java.net.NetPermission`, `java.nio.file.LinkPermission`, `java.security.SecurityPermission`, `java.sql.SQLPermission`, `javax.net.ssl.SSLPermission`, `javax.security.auth.AuthPermission`, `javax.sound.sampled.AudioPermission`, `jdk.jfr.FlightRecorderPermission`, `com.sun.jdi.JDIPermission`, `com.sun.tools.attach.AttachPermission`) have been removed from the class descriptions since these permissions are no longer supported. An API Note has been added to each concrete standard `Permission` subclass (except `javax.smartcardio.CardPermission` which is specified via JSR 268) with the following warning: "This permission cannot be used for controlling access to resources as the Security Manager is no longer supported." This API Note has also been added to the `java.security.SecureClassLoader` class since it contains methods that return permissions.
- `java.awt.Window::getWarningString` has been changed to always return `null`, since the security warning that was previously returned only applied when the Security Manager was enabled.
### APIs that supported the Security Manager
- `java.lang.Thread`: Creating a [platform thread](https://docs.oracle.com/en/java/javase/23/docs/api/java.base/java/lang/Thread.html#inheritance) will no longer capture the caller context (the so-called "inherited AccessControlContext"). This change will be welcomed by developers that have had to debug memory leak issues related to the capture and inheritance of this little known security context.
- `java.util.concurrent`:
- Three methods of `Executors` -- `privilegedCallable`, `privilegedCallableUsingCurrentClassLoader`, and `privilegedThreadFactory` -- are respecified to return objects that do not capture access control contexts, and execute actions as-is.
- The `Executors::defaultThreadFactory` method will no longer return a `ThreadFactory` that creates threads in the same thread group of the Security Manager, when enabled.
- The `ForkJoinWorkerThread` constructor will no longer use a thread group chosen by the Security Manager when the `group` parameter is `null`.
- The behavior of `ForkJoinPool` when a Security Manager is enabled has been removed -- the common pool no longer uses a factory supplying threads that have no permissions enabled.
- Java API for XML Processing (JAXP): It is strongly recommended that developers enable the "FEATURE_SECURE_PROCESSING" mode and other security features when processing XML from untrusted sources. Historically, the secure processing mode was enabled when running with a Security Manager, but was disabled otherwise. JDK-8331016 added a sample configuration file to the JDK that can be used to get strict behavior. A future JEP will propose to make the strict configuration the default.
- `java.lang.{Runtime,ProcessBuilder}`: It is strongly recommended that developers set the `jdk.lang.Process.allowAmbiguousCommands` system property to `false` to disallow ambiguous program names to `java.lang.Runtime::exec` and `java.lang.ProcessBuilder`. Historically, ambiguous input was disallowed running with a Security Manager, but was allowed otherwise (the system property defaulted to `true`). A future JDK release may change the default.
### Other Specifications
- The Java Object Serialization Specification has been updated. All references to the Security Manager, permissions, and protection domains have been removed. The API signatures for `ObjectInputStream::enableResolveObject` and `ObjectOuputStream::enableReplaceObject` have been changed to not throw `SecurityException` as it no longer applies in the absence of a Security Manager. See the attached diffs for the complete set of changes.
- The Java Remote Method Invocation Specification has been updated. All references to the Security Manager and policy have been removed. See the attached diffs for the complete set of changes.
- The Java Language Specification and the Java Virtual Machine Specification contain a few references to the Security Manager, which will be removed. These specifications will be updated for JDK 24. See [JDK-8342443](https://bugs.openjdk.org/browse/JDK-8342443) and [JDK-8342445](https://bugs.openjdk.org/browse/JDK-8342445) for more details.
- The Policy Types section of the Java Security Standard Algorithm Names Specification has been removed and links to that section from the `java.security.Policy` API have also been removed. "JavaPolicy" is not a standard `Policy` type anymore. See the attached diffs for the changes to the specification.
### Command Line Changes
It is an error to enable a Security Manager at startup:
```
$ java -Djava.security.manager -jar app.jar
$ java -Djava.security.manager="" -jar app.jar
$ java -Djava.security.manager=allow -jar app.jar
$ java -Djava.security.manager=default -jar app.jar
$ java -Djava.security.manager=com.foo.CustomSM -jar app.jar
```
Attempting to do so causes the JVM to report the error and then exit:
Error occurred during initialization of VM
java.lang.Error: A command line option has attempted to allow or enable the Security Manager. Enabling a Security Manager is not supported.
at java.lang.System.initPhase3(java.base@24/System.java:2067)
You cannot suppress this error message, nor can you reduce it to the warnings given in JDK 17 through 23.
(The five invocations of `java -D...` shown above set the system property `java.security.manager` to, respectively, the empty string, the empty string, the string `allow`, the string `default`, and the class name of a custom Security Manager.)
It is not an error to disable the installation of a custom Security Manager during run time:
```
$ java -jar app.jar
$ java -Djava.security.manager=disallow -jar app.jar
```
No warning or error message is issued at startup, and the application runs without a Security Manager, just as it did before.
(The default value of `java.security.manager` has been disallow since JDK 18, so `java -jar app.jar` means the same as `java -Djava.security.manager=disallow -jar app.jar`.)