Clarification inline below.
On 24/06/2021 11:03 am, Peter Firmstone wrote:
Hi Alan,
It is important to understand the reason for the inherited
AccessControlContext, in order to consider alternatives.
The motivation for inherited context, was simply to avoid privilege
escalation, prior to Executors.
Whenever a permission check is made, the DomainCombiner, combines the
inherited context, with the thread's current context, in case there
are any less privileged domains in the inherited context.
But there is an alternative, higher performance option, that avoids
privilege escalation for executors as well.
A ProtectionDomain with a null CodeSource has AllPermission, while a
ProtectionDomain that contains a CodeSource with a null URL has only
the Permission's given to it when created, or to blanket grant
statements in policy files.
Rather than inherit context from the calling thread, all threads upon
creation could be initialized with one shared immutable unprivileged
AccessControlContext, containing a single element array, with a
ProtectionDomain, containing a CodeSource with a null URL.
Code cannot assume that calling code is privileged, hence the
AccessController.doPrivileged method, so an unprivileged context could
replace system threads inherited context as well. There will be some
minor impacts in older code where developers create a system thread
for cleanup tasks or other things, but nothing that couldn't be worked
around, until it can be addressed properly. This is an existential
moment for Java authorization, as a developer with extensive use of
Java authorization, I would most certainly welcome this change.
This would be a simplification that enhances security. This is far
more preferable than an inherited AccessControlContext as it
eliminates any risk that Executor tasks present, where domains in the
context that creates Callable or Runnable, may not be in the inherited
thread context. JEP 411, presents an opportunity to address it.
A use case:
I would like to use virtual threads, in executors, to make blocking
secure network connections, so I don't consume too many system
threads. When network failures occur, the number of threads created
increase significantly, as blocked threads waiting on network are no
longer available to the executor.
All our executor tasks are wrapped, with AccessControlContext, using
Executors::callable(PrivilegedAction), we do this to capture the
Subject, and to grant SocketPermission (to Principles and CodeSource)
to make secure network calls from one node to another. Across the
network, the user Subject's Principals are preserved, from the thread
in the client to the thread in the server during authentication.
DeserializationPermission is granted to the user Principal's and
CodeSource in the server, so that the code cannot perform
deserialization (not to be confused with Java serialization) without
an authenticated user. The authenticated user represents the domain
from which data to be deserialized originates.
Personally I would like to see AccessController and
AccessControlContext retained, and all threads modified to be
initialized with a single shared immutable unprivileged
AccessControlContext, rather than an inherited AccessControlContext in
system threads and virtual threads that do not support any permissions
at all.
All threads except bootstrap threads in the JVM, obviously they would
need to be privileged.
--
Regards,
Peter Firmstone