无法在SPNEGO服务器上使用requests-gssapi进行身份验证

时间:2019-08-30 15:26:32

标签: python python-requests kerberos

我正在尝试使用请求通过python访问我公司的Intranet上的SAS服务,但由于身份验证失败(401),我无法使其工作。

我使用python 3.7.4,在Windows 10上请求2.22.0。到目前为止,我已经尝试/检查过:

  • requests.get(follow_redirects=True)
  • 使用HTTPBasicAuth('user', 'pass')HTTPDigestAuth()HttpNtlmAuth('user', 'pass')
  • requests_kerberos.HTTPKerberosAuth()与所有可能的参数组合一起使用,包括设置force_preemptive=True标志和principal=user@REALM。我已通过klist确认存在多个票证。
  • 安装MIT Kerberos并使用requests_gssapi.HTTPSPNEGOAuth()
  • 在git bash中使用curl命令curl -i -L -v --negotiate --user "domain\user:pswd" <protected_service_url>进行身份验证。
  • 在Internet Explorer / Chrome中打开URL显然可以。我不必在任何地方输入我的凭据,任何身份验证都在幕后进行。
  • 交换软件包遵循基本的Kerberos身份验证流程:请求受保护的服务,接收对身份验证服务的重定向,不进行身份验证就遵循重定向,获取401响应和www-authenticate: Negotiate质询,使用身份验证票进行响应。
  • 我已经检查了与Wireshark交换软件包的情况。这是来自Chrome(成功)的HTTP程序包的关键请求+响应身份验证部分:

Chrome请求

[truncated]Authorization: Negotiate YIIIsgYGKwYBBQUCoIIIpjCC...
    GSS-API Generic Security Service Application Program Interface
        OID: 1.3.6.1.5.5.2 (SPNEGO - Simple Protected Negotiation)
        Simple Protected Negotiation
            negTokenInit
                mechTypes: 4 items
                mechToken: 6082086406092a864886f71201020201006e820853308208…
                krb5_blob: 6082086406092a864886f71201020201006e820853308208…
                    KRB5 OID: 1.2.840.113554.1.2.2 (KRB5 - Kerberos 5)
                    krb5_tok_id: KRB5_AP_REQ (0x0001)
                    Kerberos

=> Chrome响应状态

HTTP/1.1 302 Found 

然后浏览器继续自动重定向到该服务。

这是requests_gssapi.HTTPSPNEGOAuth()失败的请求:

 [truncated]Authorization: Negotiate YIIHQQYJKoZIhvcSAQICAQBuggcw...
    GSS-API Generic Security Service Application Program Interface
        OID: 1.2.840.113554.1.2.2 (KRB5 - Kerberos 5)
        krb5_blob: 01006e8207303082072ca003020105a10302010ea2070305…
            krb5_tok_id: KRB5_AP_REQ (0x0001)
            Kerberos

=>响应状态

HTTP/1.1 401 Unauthorized  (text/html)

我的测试代码现在是:

# 302 response is already handled by the first GET
r1 = session.get(url)  
    if r1.status_code != 401:
        print("Error! Server authorization failed at step 2. Expected response 401 but instead got: " + str(r1.status_code))
        return None
auth_url = r1.url
# step 2: server sends 401 and WWW-Authenticate: Negotiate header
# GSS-API (SPNEGO - Simple Protected Negotiation)
r2 = session.get(auth_url, auth=HTTPSPNEGOAuth(mutual_authentication=True))

使用 requests-gssapi 库可以使我获得最接近的信息,但仍然无法通过身份验证。我不懂为什么。所使用的Kerberos票证相同。我可以看到,成功的Chrome请求和失败的python请求之间的唯一区别是OID。但是我不知道如何更改它,因为它似乎是一个库实现细节。

感谢您的帮助。

1 个答案:

答案 0 :(得分:0)

我设法解决了这个问题。因此,对于任何面临类似问题的人,请按以下步骤操作:

  • 我使用了python requests-gssapi。这是requests-kerberos的较新版本,可以放在适当的位置。
  • 但是,此库不适用于我的身份验证案例。原因是选择了错误的身份验证机制: OID:1.2.840.113554.1.2.2 (KRB5-Kerberos 5)代替了 OID:1.3.6.1.5.5.2 >(SPNEGO-简单保护协商)。幸运的是,pull request中已经有一个解决方案(截至2019年9月)。将gssapi_.py复制到本地安装中。
  • 使用以下代码,如拉取请求updated README.rst中所述:
import gssapi
import requests
from requests_gssapi import HTTPSPNEGOAuth
try:
   spnego = gssapi,mechs.Mechanism.from_sasl_name("SPNEGO")
except AttributeError:
   spnego = gssapi.OID.from_int_seq("1.3.6.1.5.5.2")
gssapi_auth = HTTPSPNEGOAuth(mech=spnego)
r = requests.get("http://example.org", auth=gssapi_auth)

完成!