<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
  </head>
  <body>
    <p>The more I think about it, allowing Thread to use a singleton
      immutable unprivileged AccessControlContext instead of the
      inherited context is the right thing to do, it achieves the
      original goal of avoiding privilege escalation, limits the the
      size of the context that needs to be checked and allows simple
      support for virtual threads.   The AccessController.doPrivileged
      method allows code to make privileged actions.<br>
    </p>
    <p>The way to implement it, for compatible transition would be:</p>
    <ol>
      <li>Implement it first in virtual threads.</li>
      <li>When stubbing out SecurityManager, change system threads to
        also use the singleton unprivileged context, instead of the
        inherited context, which must be calculated for each thread at
        creation time.</li>
      <li>Alternative option to item 2, is to make generic grants in
        policy files for affected threads (which inherited privileged
        context).<br>
      </li>
    </ol>
    <p>I recently generated some principle of least privilege policy
      files for tests:</p>
    <p><a class="moz-txt-link-freetext" href="https://github.com/pfirmstone/JGDMS/blob/trunk/qa/harness/policy/defaultsecuresharedvm.policy.new">https://github.com/pfirmstone/JGDMS/blob/trunk/qa/harness/policy/defaultsecuresharedvm.policy.new</a></p>
    <p><a class="moz-txt-link-freetext" href="https://github.com/pfirmstone/JGDMS/blob/trunk/qa/harness/policy/defaultsecuretest.policy.new">https://github.com/pfirmstone/JGDMS/blob/trunk/qa/harness/policy/defaultsecuretest.policy.new</a></p>
    <p><a class="moz-txt-link-freetext" href="https://github.com/pfirmstone/JGDMS/blob/trunk/qa/harness/policy/defaultsecurephoenix.policy.new">https://github.com/pfirmstone/JGDMS/blob/trunk/qa/harness/policy/defaultsecurephoenix.policy.new</a></p>
    <p>For the generation of these policy files, a properties file was
      provided, to populate the policy files with properties, to replace
      local and platform specific paths and file names.</p>
    <p>Note how many permissions are granted to code and principal's. 
      This ensures that other code cannot use the principal's thread for
      privileged escalation, and code cannot perform certain tasks
      without a logged in Subject.</p>
    <p>This is how we prevent deserialization (not Java deserialization)
      of untrusted data in our case, we have DeserializationPermission. 
      So not only do we ensure there's a logged in Subject, that's
      providing the data, but we are also restricting the code that is
      allowed to parse it.   Our deserialization uses constructors to
      validate invariants but, we still avoid using it to process
      untrusted data.<br>
    </p>
    <p>One pain point is SocketPermission, which doesn't allow IP
      Address subnet wild cards, hence the use of unlimited IP Address
      wild cards.  It's generally preferable not to use domain names in
      SocketPermission, due to blocking DNS calls, personally I'd like
      to replace that with RFC3986 normalization.<br>
    </p>
    <p>Note that the JGDMS SecurityManager and Policy implementations
      are performant and scalable, all hotspots in JGDMS are JDK native
      methods (Socket's basically).   The use of virtual threads, would
      provide a significant scalability improvement for JGDMS.<br>
    </p>
    <p>If we could get the proposed GuardBuilder & GuardBuilderSpi
      happening (so developers are freed from the current Permission
      implementations) as well as the proposed changes to thread
      AccessControlContext below, we would have the best authorization
      layer available.<br>
    </p>
    <p>We can still stub out SecurityManager and remove the Policy and
      Permission implementations, to reduce the maintenance burden for
      OpenJDK developers.</p>
    <p>The reality is, the overall result for us, will be much better,
      if we can retain AccessController and AccessControlContext for the
      following reasons:</p>
    <ol>
      <li>Allowing grants to be made to code and principals, to prevent
        parsing of untrusted data, while limiting the scope of those
        grants (refer to 3).</li>
      <li>Preserving current JAAS functionality, to authenticate and
        secure connections.<br>
      </li>
      <li>Limiting or preventing viral authorization checks from
        spreading to an excessive number of ProtectionDomains (viral
        Permissions).   For the libraries and JVM code that use
        doPrivileged will continue to function using common API's.<br>
      </li>
      <li>To enable developers to implement an authorization layer. 
        While this may be a small proportion of overall projects, the
        projects that do are usually significant.</li>
    </ol>
    <p>We don't require SecurityManager, a Policy or Permission
      implementations to implement an authorization layer and these
      components are the majority of the maintenance burden for OpenJDK,
      as far as I can tell at least.<br>
    </p>
    <p>Basic components required for effective authorization layer
      implementations:</p>
    <ol>
      <li>Guard, GuardBuilder and GuardBuilderSpi (or equivalent).<br>
      </li>
      <li>AccessController, AccessControlContext and DomainCombiner
        (These are difficult to re-implement in a Java version
        compatible manner, and re-implementations would not have the
        benefits of JDK support for AccessController.doPrivileged, or
        Thread context, which limits viral authorization checks).<br>
      </li>
      <li>ProtectionDomain, CodeSource and Principal</li>
      <li>JAAS, Subject and LoginModule.<br>
      </li>
      <li>GSS-API/Kerberos, JCA, JCE and JSSE.<br>
      </li>
    </ol>
    <pre class="moz-signature" cols="72">-- 
Regards,
 
Peter Firmstone</pre>
    <div class="moz-cite-prefix">On 24/06/2021 11:50 am, Peter Firmstone
      wrote:<br>
    </div>
    <blockquote type="cite"
      cite="mid:112a6b52-811f-0f57-6f21-925f9ec0f334@zeus.net.au">Clarification
      inline below.
      <br>
      <br>
      On 24/06/2021 11:03 am, Peter Firmstone wrote:
      <br>
      <blockquote type="cite">Hi Alan,
        <br>
        <br>
        It is important to understand the reason for the inherited
        AccessControlContext, in order to consider alternatives.
        <br>
        <br>
        The motivation for inherited context, was simply to avoid
        privilege escalation, prior to Executors.
        <br>
        <br>
        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.
        <br>
        <br>
        But there is an alternative, higher performance option, that
        avoids privilege escalation for executors as well.
        <br>
        <br>
        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.
        <br>
        <br>
        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.
        <br>
        <br>
        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.
        <br>
        <br>
        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.
        <br>
        <br>
        A use case:
        <br>
        <br>
        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.
        <br>
        <br>
        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.
        <br>
        <br>
        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.
        <br>
      </blockquote>
      All threads except bootstrap threads in the JVM, obviously they
      would need to be privileged.
      <br>
      <br>
    </blockquote>
    <pre class="moz-signature" cols="72">
</pre>
  </body>
</html>