Trouble with SPNEGO

classic Classic list List threaded Threaded
3 messages Options
tom
Reply | Threaded
Open this post in threaded view
|

Trouble with SPNEGO

tom
I'm having trouble with getting spnego to work, and was hoping someone might help.
I'm trying to perform a "Negotiate" authentication from a browser. My browser is Chrome on Windows 10.
The endpoint I'm connecting to us a standard jetty server (it's wrapped up in karaf), but I've implemented the actual Negotate handling manually.

If I run the server on a Linux machine, using openjdk 1.8.141, it works, I can successfully authenticate.
If I run the server on a Windows machine (same desktop machine as the browser is running on), using oracle jdk 1.8.144, I can't get it to work.

I have researched around, and it looks like there are some relevant JDK issues in the past in this area (e.g, JDK-8078439, JDK-8048194), but I should have the fixes to those. However my symptoms seem very similar to these bug reports. However, since this seems very complicated to get exactly right, I suspect I've either got something wrong in my java code, or there's some issue in my machine Active Directory configuration.

The sun.security.spnego.debug trace output in the case it doesn't work is this:

SpNegoContext.acceptSecContext: receiving token = a0 74 30 72 a0 30 30 2e 06 0a 2b 06 01 04 01 82 37 02 02 0a 06 09 2a 86 48 82 f7 12 01 02 02 06 09 2a 86 48 86 f7 12 01 02 02 06 0a 2b 06 01 04 01 82 37 02 02 1e a2 3e 04 3c 4e 54 4c 4d 53 53 50 00 01 00 00 00 97 b2 08 e2 07 00 07 00 35 00 00 00 0d 00 0d 00 28 00 00 00 0a 00 d7 3a 00 00 00 0f 54 51 55 41 52 45 4e 44 4f 4e 2d 50 43 54 45 41 4d 57 50 43
SpNegoToken NegTokenInit: reading Mechanism Oid = 1.3.6.1.4.1.311.2.2.10
SpNegoToken NegTokenInit: reading Mechanism Oid = 1.2.840.48018.1.2.2
SpNegoToken NegTokenInit: reading Mechanism Oid = 1.2.840.113554.1.2.2
SpNegoToken NegTokenInit: reading Mechanism Oid = 1.3.6.1.4.1.311.2.2.30
SpNegoToken NegTokenInit: reading Mech Token
SpNegoContext.acceptSecContext: received token of type = SPNEGO NegTokenInit
SpNegoContext: negotiated mechanism = 1.2.840.113554.1.2.2
The underlying mechanism context has not been initialized
SpNegoContext.acceptSecContext: mechanism wanted = 1.2.840.113554.1.2.2
SpNegoContext.acceptSecContext: negotiated result = ACCEPT_INCOMPLETE
SpNegoContext.acceptSecContext: sending token of type = SPNEGO NegTokenTarg
SpNegoContext.acceptSecContext: sending token = a1 14 30 12 a0 03 0a 01 01 a1 0b 06 09 2a 86 48 86 f7 12 01 02 02

I then get a second request comming in, and this fails quickly with
GSSAPI exception
GSSException: Defective token detected (Mechanism level: GSSHeader did not find the right tag)
        at sun.security.jgss.GSSHeader.<init>(Unknown Source)
        at sun.security.jgss.GSSContextImpl.acceptSecContext(Unknown Source)
        at sun.security.jgss.GSSContextImpl.acceptSecContext(Unknown Source)


When it does work, to a linux machine, I see this:
SpNegoContext.acceptSecContext: receiving token = <much longer token here>
SpNegoToken NegTokenInit: reading Mechanism Oid = 1.2.840.48018.1.2.2
SpNegoToken NegTokenInit: reading Mechanism Oid = 1.2.840.113554.1.2.2
SpNegoToken NegTokenInit: reading Mechanism Oid = 1.3.6.1.4.1.311.2.2.30
SpNegoToken NegTokenInit: reading Mechanism Oid = 1.3.6.1.4.1.311.2.2.10
SpNegoToken NegTokenInit: reading Mech Token
SpNegoContext.acceptSecContext: received token of type = SPNEGO NegTokenInit
SpNegoContext: negotiated mechanism = 1.2.840.113554.1.2.2
SpNegoContext.acceptSecContext: negotiated mech adjusted to 1.2.840.48018.1.2.2
Entered Krb5Context.acceptSecContext with state=STATE_NEW


The obvious difference here is the order of the mechanism OIDs. My first question is why this is different? It's the same browser performing both requests. So does this difference indicate something different in the kerberos service tickets the client machine has for the two services? I have had difficulties getting this far, with there being some configuration changes needed at the Active Directory level related to my Windows machine, so maybe there's still some some configuration issue there?


Tracing through the java code in SpNegoContext.java, it's clear that the condition:
                if (mechList[0].equals(mech_wanted) ||
                        (GSSUtil.isKerberosMech(mechList[0]) &&
                         GSSUtil.isKerberosMech(mech_wanted))) {

isn't true, hence GSS_acceptSecContext is never called, hence isMechContextEstablished() when it is called generates the "The underlying mechanism context has not been initialized" message. However I've no idea why that's the case.

Can someone give me more of an insight into why this isn't working for me? Given the previous bugs in this area that have been fixed, I suspect that this *can* work, which suggests to me that I've got some kind of configuration problem that is why I'm getting this.

Thanks.
Reply | Threaded
Open this post in threaded view
|

Re: Trouble with SPNEGO

Weijun Wang
1.3.6.1.4.1.311.2.2.10 is NTLM which has a much smaller token size. Java does not support NTLM as a GSS-API mechanism.

I am not sure how this happens. Normally you need to configure the browser (For example, somewhere in about:config for Firefox) on which server you can use SPNEGO. Maybe you set up one and ignored the other?

BTW, I assume you are using a single Windows KDC with 2 service principals HTTP/windows.server and HTTP/linux.server and different keytab used on those 2 servers. Is that correct?

--Max

> On Oct 11, 2017, at 8:26 PM, [hidden email] wrote:
>
> I'm having trouble with getting spnego to work, and was hoping someone might help.
> I'm trying to perform a "Negotiate" authentication from a browser. My browser is Chrome on Windows 10.
> The endpoint I'm connecting to us a standard jetty server (it's wrapped up in karaf), but I've implemented the actual Negotate handling manually.
>
> If I run the server on a Linux machine, using openjdk 1.8.141, it works, I can successfully authenticate.
> If I run the server on a Windows machine (same desktop machine as the browser is running on), using oracle jdk 1.8.144, I can't get it to work.
>
> I have researched around, and it looks like there are some relevant JDK issues in the past in this area (e.g, JDK-8078439, JDK-8048194), but I should have the fixes to those. However my symptoms seem very similar to these bug reports. However, since this seems very complicated to get exactly right, I suspect I've either got something wrong in my java code, or there's some issue in my machine Active Directory configuration.
>
> The sun.security.spnego.debug trace output in the case it doesn't work is this:
>
> SpNegoContext.acceptSecContext: receiving token = a0 74 30 72 a0 30 30 2e 06 0a 2b 06 01 04 01 82 37 02 02 0a 06 09 2a 86 48 82 f7 12 01 02 02 06 09 2a 86 48 86 f7 12 01 02 02 06 0a 2b 06 01 04 01 82 37 02 02 1e a2 3e 04 3c 4e 54 4c 4d 53 53 50 00 01 00 00 00 97 b2 08 e2 07 00 07 00 35 00 00 00 0d 00 0d 00 28 00 00 00 0a 00 d7 3a 00 00 00 0f 54 51 55 41 52 45 4e 44 4f 4e 2d 50 43 54 45 41 4d 57 50 43
> SpNegoToken NegTokenInit: reading Mechanism Oid = 1.3.6.1.4.1.311.2.2.10
> SpNegoToken NegTokenInit: reading Mechanism Oid = 1.2.840.48018.1.2.2
> SpNegoToken NegTokenInit: reading Mechanism Oid = 1.2.840.113554.1.2.2
> SpNegoToken NegTokenInit: reading Mechanism Oid = 1.3.6.1.4.1.311.2.2.30
> SpNegoToken NegTokenInit: reading Mech Token
> SpNegoContext.acceptSecContext: received token of type = SPNEGO NegTokenInit
> SpNegoContext: negotiated mechanism = 1.2.840.113554.1.2.2
> The underlying mechanism context has not been initialized
> SpNegoContext.acceptSecContext: mechanism wanted = 1.2.840.113554.1.2.2
> SpNegoContext.acceptSecContext: negotiated result = ACCEPT_INCOMPLETE
> SpNegoContext.acceptSecContext: sending token of type = SPNEGO NegTokenTarg
> SpNegoContext.acceptSecContext: sending token = a1 14 30 12 a0 03 0a 01 01 a1 0b 06 09 2a 86 48 86 f7 12 01 02 02
>
> I then get a second request comming in, and this fails quickly with
> GSSAPI exception
> GSSException: Defective token detected (Mechanism level: GSSHeader did not find the right tag)
>        at sun.security.jgss.GSSHeader.<init>(Unknown Source)
>        at sun.security.jgss.GSSContextImpl.acceptSecContext(Unknown Source)
>        at sun.security.jgss.GSSContextImpl.acceptSecContext(Unknown Source)
>
>
> When it does work, to a linux machine, I see this:
> SpNegoContext.acceptSecContext: receiving token = <much longer token here>
> SpNegoToken NegTokenInit: reading Mechanism Oid = 1.2.840.48018.1.2.2
> SpNegoToken NegTokenInit: reading Mechanism Oid = 1.2.840.113554.1.2.2
> SpNegoToken NegTokenInit: reading Mechanism Oid = 1.3.6.1.4.1.311.2.2.30
> SpNegoToken NegTokenInit: reading Mechanism Oid = 1.3.6.1.4.1.311.2.2.10
> SpNegoToken NegTokenInit: reading Mech Token
> SpNegoContext.acceptSecContext: received token of type = SPNEGO NegTokenInit
> SpNegoContext: negotiated mechanism = 1.2.840.113554.1.2.2
> SpNegoContext.acceptSecContext: negotiated mech adjusted to 1.2.840.48018.1.2.2
> Entered Krb5Context.acceptSecContext with state=STATE_NEW
>
>
> The obvious difference here is the order of the mechanism OIDs. My first question is why this is different? It's the same browser performing both requests. So does this difference indicate something different in the kerberos service tickets the client machine has for the two services? I have had difficulties getting this far, with there being some configuration changes needed at the Active Directory level related to my Windows machine, so maybe there's still some some configuration issue there?
>
>
> Tracing through the java code in SpNegoContext.java, it's clear that the condition:
>                if (mechList[0].equals(mech_wanted) ||
>                        (GSSUtil.isKerberosMech(mechList[0]) &&
>                         GSSUtil.isKerberosMech(mech_wanted))) {
>
> isn't true, hence GSS_acceptSecContext is never called, hence isMechContextEstablished() when it is called generates the "The underlying mechanism context has not been initialized" message. However I've no idea why that's the case.
>
> Can someone give me more of an insight into why this isn't working for me? Given the previous bugs in this area that have been fixed, I suspect that this *can* work, which suggests to me that I've got some kind of configuration problem that is why I'm getting this.
>
> Thanks.

tom
Reply | Threaded
Open this post in threaded view
|

Re: Trouble with SPNEGO

tom
 > 1.3.6.1.4.1.311.2.2.10 is NTLM which has a much smaller token size. Java does not support NTLM as a GSS-API mechanism.
 
Yes. So it looks like the browser is preferring NTLM and pre-emptively sending a token for that.
 
 
 > I am not sure how this happens. Normally you need to configure the browser (For example, somewhere in about:config for Firefox) on which server you can use SPNEGO. Maybe you set up one and ignored the other?
 
Chrome uses the normal Windows "internet options" configuration for this. You configure "zones" and one of the settings is "allow windows integrated authentication". Both machines in my case are in the same domain, so I *think* that it should be attempting the same kind of authentication. But I've no idea how I tell (well, other than the fact that the lists of mechanism OIDs it sends are different, so there must be *some* difference)
I get exactly the same result if I try from Firefox. Adding my host into the network.negotiate-auth.trusted-uris configuration setting doesn't have any effect. Well, without it firefox doesn't seem to do anything, but with it I get exactly the same behaviour of mechanism OIDs being sent.
I also get the same behaviour if I use a C++ HTTP client I have that just uses Windows SSPI "negotiate" package to do the same thing, but my guess is that's subject to the same basic configuration in terms of what mechanisms it will put in its list.
 
 
 
 > BTW, I assume you are using a single Windows KDC with 2 service principals HTTP/windows.server and HTTP/linux.server and different keytab used on those 2 servers. Is that correct?
 
I am, yes. I have successfully run a "java to java" example using the same keytab I'm using for this experiment, so I've successfully used a java client to perform the same authentication (at a lower level, directly, not going over HTTP, just JGSS talking to JGSS if you know what I mean, as a "unit test" of the basic code that's accepting the token that comes out of the HTTP header and attempts to perform the authentication), so I believe that the keytab is OK, and I believe that the KDC will accept my requests to authenticate users. However I have had difficulties getting that far. The Linux set up worked easily, but the Windows setup was more complex, there needs to be an actual user principal as well as the HTTP service principal. I *believe* that I'm passed that now though.
 
Issue JDK-8048194 has the same set of mechanism OIDs, and has the same basic symptom, but I'm unclear whether the issue is the same or not there.
 
The fact that the client request contains Kerberos in the mechanism OIDs suggests to me that it would be happy to process a Kerberos authentication, it's just that its first choice would be NTLM. I'm assuming that the response that the java sends back is "I can't accept your first choice, but this OID is on your list and I will accept that, so send me a token for that mechanism please". The browser response to that though appears to be a token that the java code can't read, and the error appears to come before any of the debugging output that prints any of the token information.
 
Naively, I assume that the fact that the client and the server are on the same machine isn't an issue?
 
Thanks for any help you can give me!