curlkerberosspnego

curl with --negotiate / Kerberos doesn't seem to work


I'm trying to use curl with Kerberos (against TM1). The answers in When using --negotiate with curl, is a keytab file required? seem very helpful, however, it still doesn't work for me.

No success with curl 7.29.0 and GSS-Negotiate

I followed the instructions from Avinash Reddy

$curl --version
curl 7.29.0 (x86_64-redhat-linux-gnu) libcurl/7.29.0 NSS/3.44 zlib/1.2.7 libidn/1.28 libssh2/1.8.0
Protocols: dict file ftp ftps gopher http https imap imaps ldap ldaps pop3 pop3s rtsp scp sftp smtp smtps telnet tftp
Features: AsynchDNS GSS-Negotiate IDN IPv6 Largefile NTLM NTLM_WB SSL libz unix-sockets

$/usr/share/centrifydc/kerberos/bin/kinit myuser
Password for myuser@MYREALM:

$/usr/share/centrifydc/kerberos/bin/klist
Ticket cache: FILE:/tmp/krb5cc_100123
Default principal: myuser@MYREALM

Valid starting       Expires              Service principal
01/24/2020 12:11:30  01/24/2020 22:11:30  krbtgt/MYREALM@MYREALM
        renew until 01/25/2020 12:11:26

WattsInABox says he successfully used curl 7.29.0 but for me, it doesn't seem to work:

$curl -ik -vvv --negotiate -u : -b ~/cookiejar.txt -c ~/cookiejar.txt https://mytm1server/api/v1/Configuration
* About to connect() to mytm1server port 80 (#0)
*   Trying 10.48.199.126...
* Connected to mytm1server (10.10.100.100) port 80 (#0)
* Initializing NSS with certpath: sql:/etc/pki/nssdb
* skipping SSL peer certificate verification
* SSL connection using TLS_RSA_WITH_AES_128_CBC_SHA
* Server certificate:
*       subject: CN=TM1Server,OU=TM1,O=www.ibm.com,C=US
*       start date: Mar 31 18:50:22 2015 GMT
*       expire date: Mar 27 18:50:22 2035 GMT
*       common name: TM1Server
*       issuer: CN=TM1Server,OU=TM1,O=www.ibm.com,C=US
* Server auth using Basic with user ''
> GET /api/v1/Configuration HTTP/1.1
> Authorization: Basic Og==
> User-Agent: curl/7.29.0
> Host: mytm1server:80
> Accept: */*
> Cookie: TM1SessionId=iJiQkqUDOEmdvN6A6_tHfQ
>
< HTTP/1.1 401 Unauthorized
HTTP/1.1 401 Unauthorized
< Content-Type: text/plain
Content-Type: text/plain
< Content-Length: 0
Content-Length: 0
< Connection: keep-alive
Connection: keep-alive
< OData-Version: 4.0
OData-Version: 4.0
* gss_init_sec_context() failed: : Success
< WWW-Authenticate: Negotiate, Basic realm="TM1"
WWW-Authenticate: Negotiate, Basic realm="TM1"

<
* Connection #0 to host mytm1server left intact

Notice the insanely helpful gss_init_sec_context() failed: : Success ;-)

I also tried getting a service ticket instead of a TGT:

$/usr/share/centrifydc/kerberos/bin/kinit -S tm1s/mytm1server
Password for myuser@MYREALM:

$/usr/share/centrifydc/kerberos/bin/klist
Ticket cache: FILE:/tmp/krb5cc_100771
Default principal: myuser@MYREALM

Valid starting       Expires              Service principal
01/24/2020 13:37:52  01/24/2020 23:37:52  tm1s/mytm1server@MYREALM
        renew until 01/25/2020 13:37:46

No success either:

$curl -ik --negotiate -u : -b ~/cookiejar.txt -c ~/cookiejar.txt https://mytm1server/api/v1/Configuration
HTTP/1.1 401 Unauthorized
Content-Type: text/plain
Content-Length: 0
Connection: keep-alive
OData-Version: 4.0
WWW-Authenticate: Negotiate, Basic realm="TM1"

No success with curl 7.48.0 and GSS-API and SPNEGO

On a different machine with curl 7.48.0, I followed the instructions of Michael-O except that I'm trying to go without a keytab file (we won't have that available):

$ curl --version
curl 7.61.1 (x86_64-redhat-linux-gnu) libcurl/7.61.1 OpenSSL/1.1.1c zlib/1.2.11 brotli/1.0.6 libidn2/2.0.5 libpsl/0.20.2 (+libidn2/2.0.5) libssh/0.8.5/openssl/zlib nghttp2/1.33.0
Release-Date: 2018-09-05
Protocols: dict file ftp ftps gopher http https imap imaps ldap ldaps pop3 pop3s rtsp scp sftp smb smbs smtp smtps telnet tftp
Features: AsynchDNS IDN IPv6 Largefile GSS-API Kerberos SPNEGO NTLM NTLM_WB SSL libz brotli TLS-SRP HTTP2 UnixSockets HTTPS-proxy PSL Metalink

$/usr/share/centrifydc/kerberos/bin/kinit myuser
Password for myuser@MYREALM:

$/usr/share/centrifydc/kerberos/bin/klist
Ticket cache: FILE:/tmp/krb5cc_100123
Default principal: myuser@MYREALM

Valid starting       Expires              Service principal
01/24/2020 15:19:34  01/25/2020 01:19:34  krbtgt/MYREALM@MYREALM
        renew until 01/25/2020 15:19:31

$curl -ik --negotiate -u : -b ~/cookiejar.txt -c ~/cookiejar.txt https://mytm1server/api/v1/Configuration
*   Trying 10.10.100.100...
* TCP_NODELAY set
* Connected to mytm1server (10.10.100.100) port 80 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
*   CAfile: /etc/pki/tls/certs/ca-bundle.crt
  CApath: none
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.2 (IN), TLS handshake, Certificate (11):
* TLSv1.2 (IN), TLS handshake, Server finished (14):
* TLSv1.2 (OUT), TLS handshake, Client key exchange (16):
* TLSv1.2 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.2 (OUT), TLS handshake, Finished (20):
* TLSv1.2 (IN), TLS handshake, Finished (20):
* SSL connection using TLSv1.2 / AES128-GCM-SHA256
* ALPN, server did not agree to a protocol
* Server certificate:
*  subject: C=US; O=www.ibm.com; OU=TM1; CN=TM1Server
*  start date: Mar 31 18:50:22 2015 GMT
*  expire date: Mar 27 18:50:22 2035 GMT
*  issuer: C=US; O=www.ibm.com; OU=TM1; CN=TM1Server
*  SSL certificate verify result: self signed certificate (18), continuing anyway.
> GET /api/v1/Configuration HTTP/1.1
> Host: mytm1server:80
> User-Agent: curl/7.61.1
> Accept: */*
> Cookie: TM1SessionId=m0uTI8ceIVM2TamOFMxPHg
>
< HTTP/1.1 401 Unauthorized
HTTP/1.1 401 Unauthorized
< Content-Type: text/plain
Content-Type: text/plain
< Content-Length: 0
Content-Length: 0
< Connection: keep-alive
Connection: keep-alive
< OData-Version: 4.0
OData-Version: 4.0
< WWW-Authenticate: Negotiate, Basic realm="TM1"
WWW-Authenticate: Negotiate, Basic realm="TM1"

<
* Connection #0 to host mytm1server left intact

Note that there's no gss_init_sec_context() failed: : Success here

Whether or not I manually export KRB5CCNAME=/tmp/krb5cc_100123 (shouldn't be required), it doesn't work either:

$export KRB5CCNAME=/tmp/krb5cc_100123
$curl -ik -u : -b ~/cookiejar.txt -c ~/cookiejar.txt https://mytm1server/api/v1/Configuration
HTTP/1.1 401 Unauthorized
Content-Type: text/plain
Content-Length: 0
Connection: keep-alive
Set-Cookie: TM1SessionId=mGR4OPSynQmCBIRd_B_L7g; Path=/api/; HttpOnly; Secure
WWW-Authenticate: Negotiate, Basic realm="TM1"

Now of course, one may ask if the user is even allowed to log in. But using TM1's official client, integrated login works flawlessly.

Does anyone see what's wrong, or know how to get more debug information?

Update #1

I found this blog post and it seems to do the exact same thing. I noticed, however, that the server responds with WWW-Authenticate: Negotiate whereas TM1 does with WWW-Authenticate: Negotiate, Basic realm="TM1". So I built a dummy application to simulate both cases and guess what I found: in the Negotiate-only case, curl correctly sends a second request. In the TM1 case however, it does not.


Solution

  • As it turned out, as of 7.64.0 curl doesn't support comma-separated HTTP header values in the server response.

    So this doesn't work:

    WWW-Authenticate: Negotiate, Basic realm="TM1"
    

    while this does:

    WWW-Authenticate: Negotiate