READ 1ST: Re: Authorization layer API and low level access checks

Peter Firmstone peter.firmstone at zeus.net.au
Sat Jun 26 12:05:48 UTC 2021


On 26/06/2021 3:41 pm, Peter Firmstone wrote:
>
> Apologies for multiple earlier emails, please ignore and read this 
> instead.
>
> This proposal is about stripping out and simplifying as much of the 
> dilapidated and complex SecurityManager infrastructure as possible, 
> while retaining the ability for developers to implement a better high 
> scaling and performant Authorization layer, without prohibitively 
> preventing it.
>
> Summary of Proposed Changes:
>
>  1. GuardFactory & GuardFactorySpi to provide hooks for authorization
>     checks without SecurityManager or Policy. (Note GuardFactory
>     should never return null and instead return a no-op Guard that
>     hotspot can optimize out.
>  2. Existing Permission implementations to be obtained using
>     GuardFactorySpi implementations, until their removal.  Note that
>     when SecurityManager is stubbed out and Permission implementations
>     are deprecated for removal, these should no longer be provided by
>     default, but instead need to be enabled by entries in the
>     java.security config file, in preparation for their removal.
>  3. JDK code to no longer call Permission implementations directly,
>     instances obtained using GuardFactory, when enabled in the
>     java.security configuration file.
>  4. Threads (system and virtual) updated to use a singleton
>     *unprivileged* AccessControlContext, instead of inherited
>     AccessControlContext, this is more appropriate for Executors, the
>     original inherited context was designed before Executors were
>     introduced.
>  5. Deprecation for removal of all Permission implementations from the
>     JDK platform.   The existing implementations of Permission
>     introduce unnecessary complexity; they lack sufficient flexibility
>     resulting in a proliferation of Permission grants required in
>     policy files and some make blocking network calls.
>  6. Introduce a system property to change AccessController's default
>     behaviour, disable the stack walk by default, but allow it to be
>     re-enabled with a system property, replace the stack walk array
>     result of ProtectionDomains with an *unprivileged*
>     AccessControlContext, the SubjectDomainCombiner can replace it
>     with a, AccessControlContext containing a single element array,
>     containing one ProtectionDomain with Principals.
>  7. AccessController::doPrivileged erases the DomainCombiner by
>     default, deprecate these methods for removal (make private),
>     retain doPrivilegedWithCombiner methods that preserve the
>     SubjectDomainCombiner.   Developers should replace their
>     doPrivileged methods with doPrivilegedWithCombiner.   Create a new
>     method AccessController::doUnprivileged, clear intent, to erase
>     the DomainCombiner, and use the *unprivileged*
>     AccessControlContext.  Update
>     AccessController.AccHolder.innocuousAcc to refer to an
>     *unprivileged* context, as per the definition below.
>  8. Deprecate for removal the CodeSource::implies method.
>  9. Give unique ProtectionDomain's with a meaninful CodeSource to Java
>     modules mapped to the boot loader, rather than using a Shared
>     ProtectionDomain with a null CodeSource.
> 10. Deprecate for removal AccessController::checkPermission and
>     AccessControlContext::checkPermission methods.
>
AccessController.checkPermission calls AccessControlContext.optimize, 
which invokes the DomainCombiner, prior to calling 
AccessControlContext.checkPermission

In my implementation of SecurityManager, I call 
AccessController.getContext from within a PrivilegedAction, to optimise 
a newly created AccessControlContext, (AccessController.getContext also 
calls AcessControlConext.optimize), prior to calling 
AccessControlContext.checkPermission.

I think it would be simpler however, to create a new method in 
AccessController to replace checkPermission which also calls optimize.

I think something could be done here with Stream and Consumer to perform 
the function checking ProtectionDomain's.  Needs a little more thought, 
but basically we want to be able to check each ProtectionDomain, without 
being restricted to Permission or Policy implementations.

Eg:

AccessController.stream(AccessControlContext context).forEach(domain -> 
Check::domain)

Or

AccessController.checkDomains(AccessControlContext context, 
Consumer<ProtectionDomain>)

This method would have a relevant Guard.check "RUNTIME" 
"getProtectionDomain" prior to calling AccessControlContext.optimize and 
the developer would need to make the call from a PrivilegedAction, and 
remember pass the relevant guard check for it's own AccessControlContext.

> 11. Undeprecate AccessController, AccessControlContext,
>     DomainCombiner, SubjectDomainCombiner and Subject::doAs methods,
>     while deprecating for removal methods stated in items above.
> 12. Deprecate for removal ProtectionDomain::implies,
>     ProtectionDomain::getPermissions and
>     ProtectionDomain::staticPermissionsOnly
> 13. Replace PermissionCollection type argument with Object in
>     ProtectionDomain constructors, ignore the permissions parameter,
>     and deprecate existing constructors.   Deprecate
>     PermissionCollection for removal.
> 14. Create a new constructor: ProtectionDomain(CodeSource cs,
>     ClassLoader cl, Principal[] p).
> 15. Create a new factory method
>     ProtectionDomain::newInstance(Principal[] p), to allow a weak
>     cache of ProtectionDomain instances for each Principal[], to be
>     utilised by SubjectDomainCombiner to avoid unnecessary duplication
>     of objects.   This is an optimization for
>     AccessControlContext::equals and ::hashCode methods.   Using a
>     cache of AccessControlContext, it is possible to avoid rechecking
>     authorization that has already been checked.  For example, when
>     using an Executor with many tasks, all with the same
>     AccessControlContext, you only need to check once and return the
>     same result for subsequent checks.   This is an optimization I
>     have used previously to great effect.
>
The ProtectionDomain::newInstance is just a nice to have, 
SubjectDomainCombiner already caches PD's, just seems a better place to 
cache for the following reasons:

  * Cache can be utilised by other implementations.
  * Simplification of SubjectDomainCombiner.
  * Responsibility of ProtectionDomain.

It's not an essential item, however, just seems like an opportunity for 
a little refactoring.

> To clarify what an *unprivileged* AccessControlContext is:
>
>     An instance of AccessControlContext, that contains a single
>     element array, containing a ProtectionDomain, with a null
>     ClassLoader, null Principal[] and a *non-null* CodeSource,
>     containing a null URL.
>
>     So as to distinguish between what is traditionally a JDK bootstrap
>     ProtectionDomain and unprivileged domain after
>     ProtectionDomain::getPermissions is removed.
>
> Stubbing of SecurityManager and Policy, for runtime backward 
> compatibility. Update ProtectionDomain::implies method, to *not* 
> consult with the Policy.  Note it's possible to get access to the 
> ProtectionDomain array contained within AccessControlContext using a 
> DomainCombiner.
>
> This is backward compatible with existing usages of JAAS and least 
> painful method of transition for all concerned as well as allowing 
> complete flexibility of implementation.
>
> Regards,
>
> Peter Firmstone.
>
> On 25/06/2021 3:59 pm, Peter Firmstone wrote:
>> Thanks Dalibor,
>>
>> Would targeting Java 18 be practical?
>>
>> Also it won't take long to code a prototype, just not sure of the 
>> process.
>>
>> Cheers,
>>
>> Peter.
>>
>>
>> On 24/06/2021 9:30 pm, Dalibor Topic wrote:
>>> On 24.06.2021 04:24, Peter Firmstone wrote:
>>>> Thanks Andrew,
>>>>
>>>> For the simple case, of replacing the SecurityManager stack walk, 
>>>> one could use reflection.
>>>>
>>>> Thank you for also confirming that is not possible (or at least 
>>>> very unlikely) to add a GuardBuilder to Java 8, the proposal is for 
>>>> JDK code to use a provider mechanism, to intercept permission 
>>>> checks, so custom authentication layers can be implemented, this 
>>>> could be accepted in future versions of Java, but not existing. As 
>>>> it is said, there is no harm in asking.
>>>
>>> Generally speaking, adding any public APIs to a platform release 
>>> after its specification has been published, is always going to be a 
>>> very tall order involving the JCP, among other things. It's not 
>>> really worth it, when other technical solutions, such as 
>>> multi-release JARs, already exist, that alleviate the necessity.
>>>
>>> cheers,
>>> dalibor topic
>>>
-- 
Regards,
  
Peter Firmstone

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/security-dev/attachments/20210626/932f1c4e/attachment.htm>


More information about the security-dev mailing list