<div dir="ltr">Hi Weijun,<div><br></div><div>Thanks for your help. Sorry it's taken me a while to reply, I was give other priorities over looking into this issue.</div><div><br></div><div>Your suggested workaround does indeed work. I've switched elements of the byte array around with a debugger connected to the app, and that solves the problem. Thankfully the position of the elements in the ticket seems to be predictable.</div><div><br></div><div>It's a brittle and low-level fix, but at least it works, so thanks!</div><div><br></div><div>I noticed in the bug report Internet Explorer is mentioned. We see the same behaviour with IE, Firefox and Chrome.</div></div><div class="gmail_extra"><br><div class="gmail_quote">On Thu, Apr 23, 2015 at 3:14 PM, Weijun Wang <span dir="ltr"><<a href="mailto:weijun.wang@oracle.com" target="_blank">weijun.wang@oracle.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Hi Daniel<br>
<br>
Sorry for the trouble.<span class=""><br>
<br>
On 4/23/2015 7:25 PM, Daniel Jones wrote:<br>
</span><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
Hi all,<br>
<br><span class="">
Thanks to everyone taking the time to look into this.<br>
<br>
Before I get into the detail of the technical issue, can anyone<br></span>
postulate as to *how quickly fixes tend to make it into releases of<br>
OpenJDK*? Are we talking days, weeks, or months? I'm just trying to<span class=""><br>
advise my client on the best mitigation strategy until the issue is<br>
resolved.<br>
</span></blockquote>
<br>
Oracle does not releases binaries for OpenJDK, you only get the source codes on <a href="http://hg.openjdk.java.net" target="_blank">http://hg.openjdk.java.net</a>. Once we made a fix, the changeset will be there. So if you build your own JDK, that's quite fast.<br>
<br>
If you use Oracle JDK, it has a release schedule at<br>
<br>
  <a href="https://www.java.com/en/download/faq/release_dates.xml" target="_blank">https://www.java.com/en/download/faq/release_dates.xml</a><br>
<br>
So it's months.<span class=""><br>
<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
The Spring code in question actually changed this morning to throw a<br>
more useful error:<br>
<a href="https://github.com/spring-projects/spring-security-kerberos/commit/f046bd7c69d6dad74eb06a7651cd68060b31ff6f" target="_blank">https://github.com/spring-projects/spring-security-kerberos/commit/f046bd7c69d6dad74eb06a7651cd68060b31ff6f</a><br>
<br>
    On the other hand, your program has<br>
        context.acceptSecContext(kerberosTicket, 0, kerberosTicket.length);<br>
        String user = context.getSrcName().toString();<br>
    which is not standard. The acceptSecContext call should be in a loop<br>
    until a context is established, and then you can call getSrcName().<br>
</blockquote>
<br></span>
If you look at the class spec in<br>
<br>
<br>
<a href="http://hg.openjdk.java.net/jdk8u/jdk8u-dev/jdk/file/debb4ce14251/src/share/classes/org/ietf/jgss/GSSContext.java" target="_blank">http://hg.openjdk.java.net/jdk8u/jdk8u-dev/jdk/file/debb4ce14251/src/share/classes/org/ietf/jgss/GSSContext.java</a><br>
<br>
the formal context establishment should be like<br>
<br>
     *     while (!context.isEstablished()) {<br>
     *         inToken = readToken();<br>
     *         outToken = context.acceptSecContext(inToken, 0,<br>
     *                                             inToken.length);<br>
     *         // send output token if generated<br>
     *         if (outToken != null)<br>
     *             sendToken(outToken);<br>
     *     }<br>
<br>
In your case, before 8048194, it just happens that the while loop only runs once.<br>
<br>
What is the client here? A browser?<br>
<br>
On the other hand, I am looking at your code and see if there is a workaround. Can you capture some packets and send to me? Especially I'd like the content of "kerberosTicket" in<br>
<br>
  byte[] responseToken = context.acceptSecContext(kerberosTicket, 0, kerberosTicket.length);<br>
<br>
In my experiment, the first 48 bytes look like this:<br>
<br>
0000: 60 82 02 2D 06 06 2B 06   01 05 05 02 A0 82 02 21<br>
0010: 30 82 02 1D A0 18 30 16   06 09 2A 86 48 82 F7 12<br>
0020: 01 02 02 06 09 2A 86 48   86 F7 12 01 02 02 A1 04<br>
<br>
Here, the OIDs are the 11 bytes from 0x18 and 0x23 starting with 06 09. You can see the only difference between the 2 OIDs are 82 (at 0x1D) and 86 (at 0x28). If you swap them, Java will happily accept it.<br>
<br>
Please note this is only a workaround and the real fix should be inside JDK. If your packet is bigger the 2nd byte might be 83 and you need to look a bit further for the OIDs (still starting with 06 09).<br>
<br>
Thanks<br>
Max<br>
<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><span class="">
<br>
<br>
I'm not sure that this would work. I'm not at all familiar with what is<br>
best practice in handling Kerberos tickets, but let me explain what<br>
happens at present in u40:<br>
<br></span>
 1. Spring's SunJaasKerberosTicketValidator gets a GSSContextImpl, and<br>
    calls acceptSecContext on it.<br>
 2. The GSSContextImpl calls an overloaded accetSecContext method, which<span class=""><br>
    successfully creates a SpNegoContext and assigns it as the mechCtxt<br>
    member.<br></span>
 3. GSSContextImpl#acceptSecContext then calls<br>
    SpNegoContext#acceptSecContext<br>
 4. In SpNegoContext#acceptSecContext we have the new functionality that<span class=""><br>
    only looks at the top item of the list of OIDs from the service ticket.<br></span>
 5. The inner mechContext of the SpNegoContext is not set.<br>
 6. We return back to the Spring code, with a GSSContextImpl wrapping a<br>
    SpNegoContext<br>
 7. Spring calls GSSContextImpl#getSrcName(), which delegates to<span class=""><br>
    SpNegoContext#getSrcName(), which returns null as its mechContext<br>
    member is null.<br>
</span></blockquote>
<br>
Yes.<span class=""><br>
<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
<br>
Spring passes the whole ticket into GSSContextImpl, and doesn't know<br>
about OIDs and the list of acceptable mechanisms. It seems like it's a<br>
responsibility of either SpNegoContext or GSSContextImpl to know about<br>
this list and iterate over it.<br>
</blockquote>
<br></span>
Yes. Unfortunately Java does not understand that 1st OID now.<span class=""><br>
<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
If the Spring code were to attempt a repeat, how should it know that the<br>
inner context was not set? What action should it perform next? It's<br>
passed in the ticket it knows about, and got back a populated byte[],<br>
without any exceptions. What would it use to determine that one of the<br>
side affects of GSSContextImpl#acceptSecContext hasn't succeeded?<br>
</blockquote>
<br></span>
Like what I quoted above, loop until context.isEstablished() is true. Of course, this means the client side must also coded formally to loop on its side. I don't know what the client is and not sure if its application protocol has this loop defined.<span class=""><br>
<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
Does the above make sense? Please do get in touch if I an provide any<br>
other assistance in helping with the issue, and thanks again to everyone<br>
looking into it.<br>
</blockquote>
<br></span>
Thanks.<br>
<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><span class="">
<br>
<br>
<br>
On Thu, Apr 23, 2015 at 1:58 AM, Weijun Wang <<a href="mailto:weijun.wang@oracle.com" target="_blank">weijun.wang@oracle.com</a><br></span><div><div class="h5">
<mailto:<a href="mailto:weijun.wang@oracle.com" target="_blank">weijun.wang@oracle.com</a>>> wrote:<br>
<br>
    Hi Daniel<br>
<br>
    I've read more about your bug report and know what's happening.<br>
<br>
    You are proposing 2 OIDs, [1.2.840.48018.1.2.2,<br>
    1.2.840.113554.1.2.2], 1st one being Microsoft's own krb5 OID and<br>
    2nd the standard one. Java only understands the 2nd one but before<br>
    that changeset it blindly accepts the mechToken without looking at<br>
    the OID. Since it's also krb5, the mechToken is processed correctly<br>
    and everything goes on. After the changeset, it does not recognize<br>
    the OID anymore and asks the client to send another mechToken with<br>
    1.2.840.113554.1.2.2.<br>
<br>
    I believe a lot of people is using the Microsoft OID. I will see if<br>
    it's possible to recognize both OIDs.<br>
<br>
    On the other hand, your program has<br>
<br>
        context.acceptSecContext(kerberosTicket, 0, kerberosTicket.length);<br>
        String user = context.getSrcName().toString();<br>
<br>
    which is not standard. The acceptSecContext call should be in a loop<br>
    until a context is established, and then you can call getSrcName().<br>
    Can you try that? Hopefully after the client sees the server request<br>
    for a 1.2.840.113554.1.2.2 mechToken it can send one and the server<br>
    can go on.<br>
<br>
    Thanks<br>
    Max<br>
<br>
<br>
    On 4/23/2015 7:22 AM, Weijun Wang wrote:<br>
<br>
        Hi Daniel<br>
<br>
        Thanks for the report.<br>
<br>
        In fact, the bug behind the changeset you mentioned -- 8048194<br>
        -- was<br>
        just meant to make your case work. Before that, the server blindly<br>
        accepts the mechToken and process it no matter if the OID is<br>
        supported.<br>
        Now it first looks at the OID and accept the token if it<br>
        supports the<br>
        OID; otherwise, only the negotiated result (its supported OID)<br>
        is sent<br>
        back, and waits for the client sending the correct mechToken in<br>
        the next<br>
        round.<br>
<br>
        It seems the logic above is not implemented correctly, can you<br>
        show me<br>
        the full stack of your NullPointerException? If it includes any<br>
        sensitive info you can write me privately.<br>
<br>
        Thanks<br>
        Max<br>
<br>
        On 4/23/2015 12:21 AM, Rob McKenna wrote:<br>
<br>
            Hi Daniel,<br>
<br>
            Thanks for the report, I'm cc'ing the security-dev alias.<br>
<br>
                  -Rob<br>
<br>
            On 22/04/15 13:10, Daniel Jones wrote:<br>
<br>
                Hi all,<br>
<br>
                Apologies if this is the wrong mailing list - please<br>
                direct me to the<br>
                correct one if so.<br>
<br>
                I believe I've found a bug in OpenJDK 1.8.0_40,<br>
                introduced in commit<br>
                d777e2918a77:<br>
                <a href="http://hg.openjdk.java.net/jdk8u/jdk8u40/jdk/file/d777e2918a77/src/share/classes/sun/security/jgss/spnego/SpNegoContext.java" target="_blank">http://hg.openjdk.java.net/jdk8u/jdk8u40/jdk/file/d777e2918a77/src/share/classes/sun/security/jgss/spnego/SpNegoContext.java</a><br>
<br>
<br>
<br>
                The change introduced on line 548 means that an<br>
                authentication<br>
                mechanism is<br>
                only accepted if the OID of the mechanism desired is the<br>
                *first* in the<br>
                list of mechanisms specified as acceptable in the<br>
                incoming ticket.<br>
<br>
                In the case of my current client their service tickets<br>
                are specifying 4<br>
                acceptable mechanism OIDs, but the only available<br>
                mechanism's OID<br>
                appears<br>
                second on that list. So whilst the server *can *satisfy<br>
                the ticket, the<br>
                code change on line 548 prevents this from happening.<br>
<br>
                Using the same server code, the same Kerberos KDC, and<br>
                OpenJDK 1.8.0_31,<br>
                everything works. Changing only the JDK results in the<br>
                mechContext not<br>
                being properly populated, which in turn causes a<br>
                NullPointerException<br>
                from<br>
                some Spring Security Kerberos code.<br>
<br>
                Has anyone else experienced this?<br>
<br>
<br>
<br>
<br>
<br>
<br>
--<br>
Regards,<br>
<br>
Daniel Jones<br>
EngineerBetter.com<br>
</div></div></blockquote>
</blockquote></div><br></div><br clear="all"><div><br></div>-- <br><div class="gmail_signature"><div dir="ltr">Regards,<div><br></div><div>Daniel Jones</div><div>EngineerBetter.com</div></div></div>