从Windows到Linux的HTTP协商失败

问题描述:

我正在尝试将我的本地Windows 10计算机验证为在泊坞窗容器内运行的Web服务。更具体地说,这个容器运行Hadoop服务和MIT Kerberos KDC。我在本地机器上安装了用于Windows的MIT Kerberos,并成功从KDC获得了一张票hadoop/[email protected]。当我使用容器中的相同主体进行身份验证并调用此命令时:curl -i --negotiate -u : "http://quickstart.cloudera:50070/webhdfs/v1/?op=GETFILESTATUS"我收到有效的回复。然而,从我的Windows机器一样运行的命令返回此错误:从Windows到Linux的HTTP协商失败

Error 403 GSSException: Defective token detected (Mechanism level: GSSHeader did not find the right tag) 

任何人都熟悉SSPI/GSSAPI能给我这里的问题可能是什么的一些见解?我的环境变量KRB5CCNAME=<path to ccache>设置正确。这是从我的Windows命令提示符下卷曲信息:

curl 7.52.1 (x86_64-w64-mingw32) libcurl/7.52.1 WinSSL zlib/1.2.8 WinIDN libssh2/1.7.0_DEV 
Protocols: dict file ftp ftps gopher http https imap imaps ldap ldaps pop3 pop3s rtsp scp sftp smtp smtps telnet tftp 
Features: IDN IPv6 Largefile SSPI Kerberos SPNEGO NTLM SSL libz 

让我知道,如果你需要我的环境设置的任何详细信息。

更新:

这里是我的Windows机器的完整的HTTP响应,当我运行添加了冗长的-v标志的命令。

* timeout on name lookup is not supported 
* Trying 127.0.0.1... 
* TCP_NODELAY set 
* Connected to quickstart.cloudera (127.0.0.1) port 50070 (#0) 
> GET /webhdfs/v1/?op=GETFILESTATUS HTTP/1.1 
> Host: quickstart.cloudera:50070 
> User-Agent: curl/7.52.1 
> Accept: */* 
> 
< HTTP/1.1 401 Authentication required 
HTTP/1.1 401 Authentication required 
< Cache-Control: must-revalidate,no-cache,no-store 
Cache-Control: must-revalidate,no-cache,no-store 
< Date: Fri, 10 Feb 2017 19:41:27 GMT 
Date: Fri, 10 Feb 2017 19:41:27 GMT 
< Pragma: no-cache 
Pragma: no-cache 
< Date: Fri, 10 Feb 2017 19:41:27 GMT 
Date: Fri, 10 Feb 2017 19:41:27 GMT 
< Pragma: no-cache 
Pragma: no-cache 
< Content-Type: text/html; charset=iso-8859-1 
Content-Type: text/html; charset=iso-8859-1 
< WWW-Authenticate: Negotiate 
WWW-Authenticate: Negotiate 
< Set-Cookie: hadoop.auth=; Path=/; HttpOnly 
Set-Cookie: hadoop.auth=; Path=/; HttpOnly 
< Content-Length: 1404 
Content-Length: 1404 
< Server: Jetty(6.1.26.cloudera.4) 
Server: Jetty(6.1.26.cloudera.4) 

< 
* Ignoring the response-body 
* Curl_http_done: called premature == 0 
* Connection #0 to host quickstart.cloudera left intact 
* Issue another request to this URL: 'http://quickstart.cloudera:50070/webhdfs/v1/?op=GETFILESTATUS' 
* Found bundle for host quickstart.cloudera: 0x817220 [can pipeline] 
* Re-using existing connection! (#0) with host quickstart.cloudera 
* Connected to quickstart.cloudera (127.0.0.1) port 50070 (#0) 
* Server auth using Negotiate with user '' 
> GET /webhdfs/v1/?op=GETFILESTATUS HTTP/1.1 
> Host: quickstart.cloudera:50070 
> Authorization: Negotiate TlRMTVNTUAABAAAAt4II4gAAAAAAAAAAAAAAAAAAAAAKAFopAAAADw== 
> User-Agent: curl/7.52.1 
> Accept: */* 
> 
< HTTP/1.1 403 GSSException: Defective token detected (Mechanism level: GSSHeader did not find the right tag) 
HTTP/1.1 403 GSSException: Defective token detected (Mechanism level: GSSHeader did not find the right tag) 
< Cache-Control: must-revalidate,no-cache,no-store 
Cache-Control: must-revalidate,no-cache,no-store 
< Date: Fri, 10 Feb 2017 19:41:27 GMT 
Date: Fri, 10 Feb 2017 19:41:27 GMT 
< Pragma: no-cache 
Pragma: no-cache 
< Date: Fri, 10 Feb 2017 19:41:27 GMT 
Date: Fri, 10 Feb 2017 19:41:27 GMT 
< Pragma: no-cache 
Pragma: no-cache 
< Content-Type: text/html; charset=iso-8859-1 
Content-Type: text/html; charset=iso-8859-1 
< Set-Cookie: hadoop.auth=; Path=/; HttpOnly 
Set-Cookie: hadoop.auth=; Path=/; HttpOnly 
< Content-Length: 1546 
Content-Length: 1546 
< Server: Jetty(6.1.26.cloudera.4) 
Server: Jetty(6.1.26.cloudera.4) 

< 
<html> 
<head> 
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"/> 
<title>Error 403 GSSException: Defective token detected (Mechanism level: GSSHeader did not find the right tag)</title> 
</head> 
<body><h2>HTTP ERROR 403</h2> 
<p>Problem accessing /webhdfs/v1/. Reason: 
<pre> GSSException: Defective token detected (Mechanism level: GSSHeader did not find the right tag)</pre></p><hr /><i><small>Powered by Jetty://</small></i><br/> 
<br/> 
<br/> 
<br/> 
<br/> 
<br/> 
<br/> 
<br/> 
<br/> 
<br/> 
<br/> 
<br/> 
<br/> 
<br/> 
<br/> 
<br/> 
<br/> 
<br/> 
<br/> 
<br/> 

</body> 
</html> 
* Curl_http_done: called premature == 0 
* Closing connection 0 

相反,这是运行我的容器内的同一命令的响应:

* About to connect() to quickstart.cloudera port 50070 (#0) 
* Trying 172.18.0.2... connected 
* Connected to quickstart.cloudera (172.18.0.2) port 50070 (#0) 
> GET /webhdfs/v1/?op=GETFILESTATUS HTTP/1.1 
> User-Agent: curl/7.19.7 (x86_64-redhat-linux-gnu) libcurl/7.19.7 NSS/3.15.3 zlib/1.2.3 libidn/1.18 libssh2/1.4.2 
> Host: quickstart.cloudera:50070 
> Accept: */* 
> 
< HTTP/1.1 401 Authentication required 
HTTP/1.1 401 Authentication required 
< Cache-Control: must-revalidate,no-cache,no-store 
Cache-Control: must-revalidate,no-cache,no-store 
< Date: Fri, 10 Feb 2017 21:15:39 GMT 
Date: Fri, 10 Feb 2017 21:15:39 GMT 
< Pragma: no-cache 
Pragma: no-cache 
< Date: Fri, 10 Feb 2017 21:15:39 GMT 
Date: Fri, 10 Feb 2017 21:15:39 GMT 
< Pragma: no-cache 
Pragma: no-cache 
< Content-Type: text/html; charset=iso-8859-1 
Content-Type: text/html; charset=iso-8859-1 
< WWW-Authenticate: Negotiate 
WWW-Authenticate: Negotiate 
< Set-Cookie: hadoop.auth=; Path=/; HttpOnly 
Set-Cookie: hadoop.auth=; Path=/; HttpOnly 
< Content-Length: 1404 
Content-Length: 1404 
< Server: Jetty(6.1.26.cloudera.4) 
Server: Jetty(6.1.26.cloudera.4) 

< 
* Ignoring the response-body 
* Connection #0 to host quickstart.cloudera left intact 
* Issue another request to this URL: 'http://quickstart.cloudera:50070/webhdfs/v1/?op=GETFILESTATUS' 
* Re-using existing connection! (#0) with host quickstart.cloudera 
* Connected to quickstart.cloudera (172.18.0.2) port 50070 (#0) 
* Server auth using GSS-Negotiate with user '' 
> GET /webhdfs/v1/?op=GETFILESTATUS HTTP/1.1 
> Authorization: Negotiate YIICkQYJKoZIhvcSAQICAQBuggKAMIICfKADAgEFoQMCAQ6iBwMFAAAAAACjggGBYYIBfTCCAXmgAwIBBaEKGwhDTE9VREVSQaImMCSgAwIBA6EdMBsbBEhUVFAbE3F1aWNrc3RhcnQuY2xvdWRlcmGjggE8MIIBOKADAgESoQMCAQKiggEqBIIBJnWbXp9WlAVk0nGIqD7T25On1+OCPzXDX/aoH01FTjJbEwrYj4cMML7Tf6jaKDIANEh57kTJOvPknL3CWHI1c3LeNpt1Ir8H2M3Zvk91HpbWXzv5WJTeUOK9L6zTaKFEs/dKQgD7VzmHKDJtMyVKQWLLVU8JuyKAV6iM4FvxfZ+WDF8QCk7pxwjgX1OT7jv9jR28MPpsIweqUYYnneJxVTsxgmsHdOvj5wpMGy9RA9R8jtR+Wh3l5r3a3zcUTmGwAqY+NXhBkviSTw+DgitnipYh5tXBRhNqGfk86qWAdodGgL+SdkwwGsq91PyYQiMCLXjWx90aBOEFeZLDyqBaXlMIZ3TT3urUQEuB206+8KNw1n6N6+u+ZY4QT7NJyVZqHbnOR5V5maSB4TCB3qADAgESooHWBIHTyaBY3PormkycaX9uf/lLe6ISYnItZikJqslAGpJVnla2HXYvhFjqn5yr8td1pw3zzdnDEZx3a9EylIrRQD5IoIvHCzd0mlJhHFj4xxISM5hxlMiL8DewMjGsVcDveqpHw1SyxIsrEPOhe62HuRXS7c1Z9kYkP6KldzyAJOttOVYCuL36hOxwEFqJtbWk1/f9gfTdzmxQmEASM3/wsj2Q/WYCZY/hazDIz6dmHsyla/F6NXGK0BwRnHHBCqSHe7GdWmBDNjHiuo6R0/YvqTl5Uvf0Rw== 
> User-Agent: curl/7.19.7 (x86_64-redhat-linux-gnu) libcurl/7.19.7 NSS/3.15.3 zlib/1.2.3 libidn/1.18 libssh2/1.4.2 
> Host: quickstart.cloudera:50070 
> Accept: */* 
> 
< HTTP/1.1 200 OK 
HTTP/1.1 200 OK 
< Cache-Control: no-cache 
Cache-Control: no-cache 
< Expires: Fri, 10 Feb 2017 21:15:39 GMT 
Expires: Fri, 10 Feb 2017 21:15:39 GMT 
< Date: Fri, 10 Feb 2017 21:15:39 GMT 
Date: Fri, 10 Feb 2017 21:15:39 GMT 
< Pragma: no-cache 
Pragma: no-cache 
< Expires: Fri, 10 Feb 2017 21:15:39 GMT 
Expires: Fri, 10 Feb 2017 21:15:39 GMT 
< Date: Fri, 10 Feb 2017 21:15:39 GMT 
Date: Fri, 10 Feb 2017 21:15:39 GMT 
< Pragma: no-cache 
Pragma: no-cache 
< Content-Type: application/json 
Content-Type: application/json 
< Set-Cookie: hadoop.auth="u=hadoop&p=hadoop/[email protected]&t=kerberos&e=1486797339425&s=BqBHGJ+/FxxeSR0ayBXHOrfPkwU="; Path=/; HttpOnly 
Set-Cookie: hadoop.auth="u=hadoop&p=hadoop/[email protected]&t=kerberos&e=1486797339425&s=BqBHGJ+/FxxeSR0ayBXHOrfPkwU="; Path=/; HttpOnly 
< Transfer-Encoding: chunked 
Transfer-Encoding: chunked 
< Server: Jetty(6.1.26.cloudera.4) 
Server: Jetty(6.1.26.cloudera.4) 

< 
* Connection #0 to host quickstart.cloudera left intact 
* Closing connection #0 
{"FileStatus":{"accessTime":0,"blockSize":0,"childrenNum":5,"fileId":16385,"group":"supergroup","length":0,"modificationTime":1459909590753,"owner":"hdfs","pathSuffix":"","permission":"755","replication":0,"storagePolicy":0,"type":"DIRECTORY"}} 
+0

'curl -v'给出了更多细节? – rogerdpack

+0

当我运行命令时,你是否指''-v'作为详细设置?我会将结果添加到原始问题中。 – ejang

答案是在这种情况下很容易。 Windows上的卷曲是用SSPI编译的。当SSPI被请求执行SPNEGO时,它会尝试在此处失败的Kerberos。可能“在数据库中找不到服务器”(使用Wireshark),然后回退到NTLM。它发出了一个原始的NTLM令牌您JGSS支持的服务器,拒绝令牌,因为

  1. 这不是SPNEGO包裹道理,但原始NTLM令牌
  2. Java不支持NTLM

Here是示例代码,如何拦截此信息并用有意义的消息进行响应。引发Hadoop的问题。

此外,Linux上的Curl版本7.19.7是非常古老且不安全的,您应该立即升级,并且Jetty上的SPNEGO Authenticator已损坏,因为它没有使用上下文完成令牌进行响应。总之,整个认证不应该被信任,因为它是错误的。见RFC 7546