使用Python进行SSO的SPNEGO(Kerberos令牌生成/验证)
我正在尝试实现一个简单的单点登录(SSO)场景,其中一些参与的服务器是Windows(IIS)系统。看起来SPNEGO是一个不错的选择。
这是具体的场景:
- 用户使用用户名和密码登录我的SSO服务。我通过某种机制来验证他的身份。
- 在某个时候,用户想要访问应用程序A。
- 用户对应用程序A的请求被SSO服务拦截。SSO服务使用SPNEGO来让用户登录应用程序A:
- SSO服务访问应用程序A的网页,得到一个“WWW-Authenticate: Negotiate”的响应。
- SSO服务代表用户生成一个“Authorization: Negotiate xxx”的响应,并将其发送给应用程序A。用户现在已经登录到应用程序A。
- SSO服务会拦截用户后续对应用程序A的请求,在转发给应用程序A之前,插入Authorization头。
这样做听起来对吗?
我现在需要两样东西(至少我能想到的):
- 能够代表用户生成“Authorization: Negotiate xxx”令牌,最好是用Python实现。
- 能够在Python中验证“Authorization: Negotiate xxx”头(这是项目后面的部分)。
3 个回答
我花了很长时间在找类似的东西(在Linux上),这让我多次来到这个页面,但一直没有找到答案。所以我想分享一下我找到的解决办法:
我使用的网络服务器是Apache,配合mod_auth_kerb。它已经在一个活动目录的单点登录环境中运行了很长时间。
在此之前,我已经能做到以下几点:
- 在Linux上使用Chromium浏览器进行单点登录(前提是正确设置了krb5,并且kinit user@domain可以正常工作)
- 用Python连接并通过pywin32包的sspi实现单点登录,代码大概是这样的:
sspi.ClientAuth("Negotiate", targetspn="http/%s" % host)
接下来这段代码就是我解决问题的关键,让Python在Linux上通过Kerberos实现单点登录(使用python-gssapi):
in_token=base64.b64decode(neg_value)
service_name = gssapi.Name("HTTP@%s" % host, gssapi.C_NT_HOSTBASED_SERVICE)
spnegoMechOid = gssapi.oids.OID.mech_from_string("1.3.6.1.5.5.2")
ctx = gssapi.InitContext(service_name,mech_type=spnegoMechOid)
out_token = ctx.step(in_token)
buffer = sspi.AuthenticationBuffer()
outStr = base64.b64encode(out_token)
看看这个教程:http://spnego.sourceforge.net/credential_delegation.html。它似乎正好是在做你想要做的事情。
这正是苹果公司在他们的日历服务器中所做的。他们使用了一个python gssapi库来处理过程中的kerberos部分,以实现SPNEGO。
如果你想查看服务器认证的部分,可以去CalendarServer/twistedcaldav/authkerb.py文件里找。kerberos模块是用C语言写的,但它没有什么有用的文档说明。不过,PyKerberos/pysrc/kerberos.py里有所有的函数定义。
这是svn主干的链接:
http://svn.calendarserver.org/repository/calendarserver/CalendarServer/trunk
http://svn.calendarserver.org/repository/calendarserver/PyKerberos/trunk