Bug 1093348

Summary: Kerberos authentication fails when server gives two 'WWW-Authenticate: Negotiate' headers
Product: [Fedora] Fedora Reporter: David Woodhouse <dwmw2>
Component: curlAssignee: Kamil Dudka <kdudka>
Status: CLOSED ERRATA QA Contact: Fedora Extras Quality Assurance <extras-qa>
Severity: unspecified Docs Contact:
Priority: unspecified    
Version: 20CC: dwmw2, kdudka, paul
Target Milestone: ---Keywords: Patch
Target Release: ---   
Hardware: Unspecified   
OS: Unspecified   
Whiteboard:
Fixed In Version: curl-7.29.0-19.fc19 Doc Type: Bug Fix
Doc Text:
Story Points: ---
Clone Of: Environment:
Last Closed: 2014-05-16 10:08:41 UTC Type: Bug
Regression: --- Mount Type: ---
Documentation: --- CRM:
Verified Versions: Category: ---
oVirt Team: --- RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: --- Target Upstream Version:
Embargoed:
Bug Depends On:    
Bug Blocks: 1754736    
Attachments:
Description Flags
http: avoid auth failure on a duplicated header [NOT TESTED] none

Description David Woodhouse 2014-05-01 13:42:37 UTC
We send an initial request, and we get back a response which looks like this:

HTTP/1.1 401 Unauthorized
server: IA Web Server
connection: close
content-type: text/html; charset=UTF-8
www-authenticate: Negotiate
www-authenticate: Negotiate
...

It looks like curl sees the first WWW-Authenticate: header and quite sanely calls gss_init_sec_context() once...

Breakpoint 1, gss_init_sec_context (minor_status=minor_status@entry=0x7fffffffd110, 
    claimant_cred_handle=claimant_cred_handle@entry=0x0, context_handle=context_handle@entry=0x634af8, target_name=0x813520, 
    req_mech_type=req_mech_type@entry=0x0, req_flags=6, time_req=time_req@entry=0, 
    input_chan_bindings=input_chan_bindings@entry=0x0, input_token=input_token@entry=0x7fffffffd120, 
    actual_mech_type=actual_mech_type@entry=0x0, output_token=output_token@entry=0x7fffffffd130, 
    ret_flags=ret_flags@entry=0x0, time_rec=time_rec@entry=0x0) at g_init_sec_context.c:113
113	{
(gdb) p *input_token
$2 = {length = 0, value = 0x0}
(gdb) fini
Run till exit from #0  gss_init_sec_context (minor_status=minor_status@entry=0x7fffffffd110, 
    claimant_cred_handle=claimant_cred_handle@entry=0x0, context_handle=context_handle@entry=0x634af8, target_name=0x813520, 
    req_mech_type=req_mech_type@entry=0x0, req_flags=6, time_req=time_req@entry=0, 
    input_chan_bindings=input_chan_bindings@entry=0x0, input_token=input_token@entry=0x7fffffffd120, 
    actual_mech_type=actual_mech_type@entry=0x0, output_token=output_token@entry=0x7fffffffd130, 
    ret_flags=ret_flags@entry=0x0, time_rec=time_rec@entry=0x0) at g_init_sec_context.c:113
Curl_gss_init_sec_context (data=data@entry=0x62c110, minor_status=minor_status@entry=0x7fffffffd110, 
    context=context@entry=0x634af8, target_name=<optimized out>, input_chan_bindings=input_chan_bindings@entry=0x0, 
    input_token=input_token@entry=0x7fffffffd120, output_token=output_token@entry=0x7fffffffd130, 
    ret_flags=ret_flags@entry=0x0) at curl_gssapi.c:67
67	}
Value returned is $3 = 1

It obtained a valid ticket for the corresponding HTTP service here, and generated a suitable token for sending to the HTTP server, returning GSS_S_CONTINUE_NEEDED.

(gdb) p *output_token
$5 = {length = 3671, value = 0x90f5b0}
(gdb) x/40xb 0x90f5b0
0x90f5b0:	0x60	0x82	0x0e	0x53	0x06	0x09	0x2a	0x86
0x90f5b8:	0x48	0x86	0xf7	0x12	0x01	0x02	0x02	0x01
0x90f5c0:	0x00	0x6e	0x82	0x0e	0x42	0x30	0x82	0x0e
0x90f5c8:	0x3e	0xa0	0x03	0x02	0x01	0x05	0xa1	0x03
0x90f5d0:	0x02	0x01	0x0e	0xa2	0x07	0x03	0x05	0x00

OK, so far so good... 

(gdb) c
Continuing.
< www-authenticate: Negotiate
www-authenticate: Negotiate

Breakpoint 1, gss_init_sec_context (minor_status=minor_status@entry=0x7fffffffd110, 
    claimant_cred_handle=claimant_cred_handle@entry=0x0, context_handle=context_handle@entry=0x634af8, target_name=0x813520, 
    req_mech_type=req_mech_type@entry=0x0, req_flags=6, time_req=time_req@entry=0, 
    input_chan_bindings=input_chan_bindings@entry=0x0, input_token=input_token@entry=0x7fffffffd120, 
    actual_mech_type=actual_mech_type@entry=0x0, output_token=output_token@entry=0x7fffffffd130, 
    ret_flags=ret_flags@entry=0x0, time_rec=time_rec@entry=0x0) at g_init_sec_context.c:113

Er, but now it hits the second WWW-Authenticate: header, still in the *first* (and only) HTTP response from the server. Invokes gss_init_sec_context() again, with the same context handle, and an empty input_token again.

(gdb) p *input_token
$6 = {length = 0, value = 0x0}
(gdb) fini
Run till exit from #0  gss_init_sec_context (minor_status=minor_status@entry=0x7fffffffd110, 
    claimant_cred_handle=claimant_cred_handle@entry=0x0, context_handle=context_handle@entry=0x634af8, target_name=0x813520, 
    req_mech_type=req_mech_type@entry=0x0, req_flags=6, time_req=time_req@entry=0, 
    input_chan_bindings=input_chan_bindings@entry=0x0, input_token=input_token@entry=0x7fffffffd120, 
    actual_mech_type=actual_mech_type@entry=0x0, output_token=output_token@entry=0x7fffffffd130, 
    ret_flags=ret_flags@entry=0x0, time_rec=time_rec@entry=0x0) at g_init_sec_context.c:113
Curl_gss_init_sec_context (data=data@entry=0x62c110, minor_status=minor_status@entry=0x7fffffffd110, 
    context=context@entry=0x634af8, target_name=<optimized out>, input_chan_bindings=input_chan_bindings@entry=0x0, 
    input_token=input_token@entry=0x7fffffffd120, output_token=output_token@entry=0x7fffffffd130, 
    ret_flags=ret_flags@entry=0x0) at curl_gssapi.c:67
67	}
Value returned is $7 = 589824
(gdb) p/x 589824
$8 = 0x90000

This time we get GSS_S_DEFECTIVE_TOKEN. It wasn't expecting an empty token now.

So we end up sending a further request to the server, with *no* Authentication: header. Get another response from the server with two 'WWW-Authenticate: Negotiate' headers, call gss_init_sec_context() for the same context another two times with empty input tokens, getting GSS_S_DEFECTIVE_TOKEN each time. And authentication fails.

Comment 1 David Woodhouse 2014-05-01 13:44:03 UTC
FWIW firefox also fails, now the server has started doing this. I don't actually think the server is wrong, is it? Just misguided, perhaps. I haven't debugged the firefox behaviour; curl was easier...

Comment 2 Kamil Dudka 2014-05-02 11:35:31 UTC
(In reply to David Woodhouse from comment #1)
> FWIW firefox also fails, now the server has started doing this. I don't
> actually think the server is wrong, is it?

If I understand it correctly, it is not curl's behavior what changed.  The server in question just started to send duplicated HTTP headers for no apparent reason.

I believe it makes sense to get curl ready for this.  We should probably also notify the maintainers of the server as the change seems to break many clients.

Comment 3 Kamil Dudka 2014-05-05 12:57:05 UTC
Created attachment 892526 [details]
http: avoid auth failure on a duplicated header [NOT TESTED]

Comment 4 Kamil Dudka 2014-05-05 12:58:06 UTC
David, could you please check whether the attached patch fixes the problem?

Comment 5 David Woodhouse 2014-05-08 14:25:42 UTC
Yes, that fixes it. Thanks.

(Firefox is *not* failing, btw. It did fail... and that's why I was looking with curl. But by the time I looked again, Firefox was working again and I don't know why it ever didn't).

Comment 6 Kamil Dudka 2014-05-09 05:38:43 UTC
Thanks you for testing the patch, David!  I have proposed the patch upstream:

http://thread.gmane.org/gmane.comp.web.curl.library/42368

Hopefully it was not a change on the server what made it work in both cases :-)

Comment 7 Kamil Dudka 2014-05-09 11:47:47 UTC
upstream commit:

https://github.com/bagder/curl/commit/ec5fde24

Comment 8 Kamil Dudka 2014-05-09 21:46:09 UTC
fixed in curl-7.36.0-4.fc21

Comment 9 Fedora Update System 2014-05-10 18:13:32 UTC
curl-7.29.0-19.fc19 has been submitted as an update for Fedora 19.
https://admin.fedoraproject.org/updates/curl-7.29.0-19.fc19

Comment 10 Fedora Update System 2014-05-10 18:13:45 UTC
curl-7.32.0-10.fc20 has been submitted as an update for Fedora 20.
https://admin.fedoraproject.org/updates/curl-7.32.0-10.fc20

Comment 11 Fedora Update System 2014-05-12 05:22:46 UTC
Package curl-7.32.0-10.fc20:
* should fix your issue,
* was pushed to the Fedora 20 testing repository,
* should be available at your local mirror within two days.
Update it with:
# su -c 'yum update --enablerepo=updates-testing curl-7.32.0-10.fc20'
as soon as you are able to.
Please go to the following url:
https://admin.fedoraproject.org/updates/FEDORA-2014-6241/curl-7.32.0-10.fc20
then log in and leave karma (feedback).

Comment 12 Fedora Update System 2014-05-16 10:08:41 UTC
curl-7.32.0-10.fc20 has been pushed to the Fedora 20 stable repository.  If problems still persist, please make note of it in this bug report.

Comment 13 Fedora Update System 2014-05-26 23:58:24 UTC
curl-7.29.0-19.fc19 has been pushed to the Fedora 19 stable repository.  If problems still persist, please make note of it in this bug report.