On 26/04/2022 6:28 pm, Alan Bateman wrote:
On 25/04/2022 13:53, David Lloyd wrote:
Nothing in the proposal causes splitting or delegation of
responsibilities. It is _only_ about preserving security checkpoints
in the JDK, which *add* a layer of checks to what the container might
already provide. Nothing is being subtracted, and thus I find it hard
to accept that preserving these checks somehow reduces security
overall.
"preserving security checkpoints in the JDK" suggests just leaving the
calls do AccessController.doPrivileged and
SecurityManager.checkPermission in place. That amounts to putting a
tax on every feature, every JEP, and all ongoing maintenance of the
platform. If there is refactoring or a change that forgets to insert a
checkPermission somewhere then we have a security issue and everything
that goes along with that. No thanks!
What about ensuring that all network access occurs through a single
location that we can instrument?
It would be nice to leave AccessController calls in place, oh well, such
is life.
I think Martin is right that hooking authorization libraries into low
level libraries isn't the right way to do this. Aside from the
complexity methods I would add that threads pools or any hand-off
between threads will typically break when the context is not carried.
Yes, we went to a lot of trouble to ensure context is preserved through
executors and other thread calls, for executors, it was simple enough to
decorate a Callable. However this is successful, in that our
RemoteEvent's and Event listeners use the preserved AccessControlContext
to establish and authenticate secure connections.
One other point about authorization libraries wanting to hook into low
level code is that it's a minefield of potential issues with recursive
initialization, stack overflows and some really hard to diagnose
issues. JDK-8155659 [1] is one report that comes to mind.
Yes, I have also come across this problem, I use a thread local to
detect the recursion, in try finally blocks.
https://github.com/pfirmstone/JGDMS/blob/c1edf5892306f24f8f97f459f499dec54984b08f/JGDMS/jgdms-platform/src/main/java/org/apache/river/api/security/CombinerSecurityManager.java#L347
One must also be aware of class loading, to ensure necessary classes are
loaded at the right time.
The following is an example of a complex issue, which was solved using
immutability, by avoiding shared state between threads and avoiding
blocking where possible. Java's PermissionCollection implementations
are a minefield of synchronization, so we thread confined
PermissionCollection. We avoided caching permission check results as
Java's policy cache is a huge performance killer. There is also the
issue of DNS calls made in URL and URLClassLoader, so we fixed those
issues too. Instead of relying on DNS we use RFC3986 and RFC5952
normalization. The performance difference as you might imagine by
removing blocking network calls and replacing it with immutable
normalized forms was huge.
https://github.com/pfirmstone/JGDMS/blob/c1edf5892306f24f8f97f459f499dec54984b08f/JGDMS/jgdms-platform/src/main/java/net/jini/security/policy/DynamicPolicyProvider.java#L265
https://github.com/pfirmstone/JGDMS/blob/trunk/JGDMS/jgdms-platform/src/main/java/org/apache/river/api/security/ConcurrentPolicyFile.java
-Alan
[1] https://bugs.openjdk.java.net/browse/JDK-8155659
It's just such a shame that we achieved so much and OpenJDK is pulling
the rug from underneath us.
Regards,
Peter.