Django中通过GSSAPI进行的用户授权以及将用户权限委派给服务器

最近,我和我的同事们需要在我们的项目中实施透明(SSO)授权。 现在有很多关于该主题的信息,尤其是俄语。 因此,决定与后代共享这种功能的实现。

因此任务如下:必须通过GSSAPI配置从用户到服务器的透明授权,然后才能代表该用户访问数据库。

我们有:

  • 配置的Kerberos + LDAP服务器
  • PostgreSQL服务器配置为仅由GSSAPI授权
  • Django + UWSGI + nginx应用服务器,配置了Kerberos

最初的想法是将应用程序中的用户授权委派给Web服务器,在Web服务器上设置GSSAPI授权,而Django则表明我们将使用RemoteUser。 作为此描述的一部分,我将不讨论如何配置nginx以使其在GSSAPI上工作,以及如何将Django委派给Web服务器授权,这是一个有据可查的部分,并且有很多关于此的文章。 经过调试和测试,我们意识到这绝对不是我们所需要的。 是的,我们可以授权并获取用户主体名称,但是我们无权代表该用户执行任何操作。

然后,我们尝试在Internet上找到有价值的东西。 他们相对成功,并且找到了以下针对Django的软件包: django-kerberosdjango-auth-spnegodjango-auth-kerbero 。 实际上,所有这些程序包都做相同的事情,有些程序很长时间没有更新,并且不得不长时间“与手鼓跳舞”,因此至少有一些工作。 他们提供了与nginx捆绑包(GSSAPI)+ Django(RemouteUser)相同的功能。 他们所有人都通过源代码帮助解决了这个问题。

接下来,发现以下用于在Python中使用GSSAPI的软件包: ccs-pykerberospython-gssapi ,实际上它们将Python2中的RFC2744和RFC4559标准的实现导入。 使用ccs-pykerberos软件包,我们设法实现了预期的功能,然后我将展示一些代码,其中实现了与LDAP和用户的通信,并代表他对数据库进行查询。

from django.shortcuts import render from django.template.response import TemplateResponse import kerberos import psycopg2 def index(request): if 'HTTP_AUTHORIZATION' in request.META: kind, initial_client_token = request.META['HTTP_AUTHORIZATION'].split(' ', 1) if kind == 'Negotiate': service = 'HTTP@django-server-pricipal.che.ru' _ignore_result, krb_context = kerberos.authGSSServerInit(service) kerberos.authGSSServerStep(krb_context, initial_client_token) principal = kerberos.authGSSServerUserName(krb_context) _ignore_result = kerberos.authGSSServerStoreDelegate(krb_context) conn = psycopg2.connect( host='postgresql-server-host', user=principal, dbname='request-db', ) cursor = conn.cursor() cursor.execute("SELECT version()") records = cursor.fetchall() else: unauthorized_template_name = 'gssapi_test/unauthorized.html' response = TemplateResponse(request, 'gssapi_test/index.html', status=401) response['WWW-Authenticate'] = 'Negotiate' return response content = {'records': records} return render(request, 'gssapi_test/index.html', content) 

首先,我们需要检查是否已向我们提供授权标头,如果没有,则应发送带有Negotiate的标头作为响应,然后再次等待Negotiate用户的令牌。 该令牌看起来像一个用base64编码的大鞋带。 收到令牌后,我们使用authGSSServerInit()函数在LDAP服务中初始化(授权)应用程序的服务器。 接下来,我们将使用authGSSServerStep()函数代表用户在LDAP服务中进行授权,仅用于从标头接收的令牌。 然后,当在数据库中执行查询时,我们将获得用户的主体,将用作用户。 另外,我们需要创建一个Kerberos bitel缓存,该缓存将自动用于在PostgreSQL中使用authGSSServerStoreDelegate()函数对我们进行授权。 此功能仅在此软件包的最新版本中可用,因此您需要使用git克隆源并进行构建。

浏览器应配置为返回协商,默认情况下禁用此选项。 所有测试均在CentOS7的Firefox上进行,并且CentOS7已安装在所有服务器上。

此外,我们可能会遇到一个问题,即由我们的函数生成的票证缓存对于我们的流程将是不可见的,因此,我们将获得未在GSSAPI中授权用户的信息。 通过在krb5.conf中设置票证缓存可以解决此问题。 为了以防万一,我将举例说明我们的配置:

/etc/krb5.conf
 includedir /etc/krb5.conf.d/ includedir /var/lib/sss/pubconf/krb5.include.d/ [libdefaults] default_realm = DOMAIN.RU dns_lookup_realm = false dns_lookup_kdc = false rdns = false ticket_lifetime = 24h forwardable = true udp_preference_limit = 0 #    -    #default_ccache_name = KEYRING:persistent:%{uid} #    KRB5_KTNAME     default_keytab_name = FILE:/etc/httpd/http.keytab [realms] DOMAIN.RU = { kdc = ldap-server-host.domain.ru:88 master_kdc = ldap-server-host.domain.ru:88 admin_server = ldap-server-host.domain.ru:749 kpasswd_server = ldap-server-host.domain.ru:464 default_domain = domain.ru pkinit_anchors = FILE:/etc/domain/ca.crt } [domain_realm] .domain.ru = DOMAIN.RU domain.ru = DOMAIN.RU .domain.ru = DOMAIN.RU 


创建这段代码是为了帮助您理解授权和授权的发生方式,然后借助此知识,您可以构建授权装饰器以及与数据库的通信反向链接。 ccs-pykerberos软件包由Apple分别针对其内部需求而开发,我将提供指向他们使用它们的代码的链接。 他帮助我们了解了他们开发的ccs-calendarserver /twistedcaldav/authkerb.py ,对我们有很大帮助

有用的链接


Source: https://habr.com/ru/post/zh-CN427839/


All Articles