GSSAPIによるDjangoでのユーザー認証とサーバーへのユーザー権限の委任

最近、同僚と私は、プロジェクトに透過(SSO)認証を実装する必要がありました。 現在、特にロシア語で、このトピックに関する多くの情報があります。 このため、このような機能の実装を子孫と共有することが決定されました。



そのため、タスクは次のとおりです。ユーザーからサーバーへのGSSAPIを介した透過的な承認を構成し、このユーザーに代わってデータベースにアクセスできるようにする必要がありました。



持っていた:





最初は、アプリケーションのユーザー認証をWebサーバーに委任し、GSSAPI認証を設定し、DjangoがRemoteUserで作業することを示すことでした。 この説明の一部として、GSSAPIで動作するようにnginxを構成する方法、およびWebサーバーに認証を委任するためのDjangoの方法については説明しません。 チューニングとテストの後、これは絶対に必要なものではないことがわかりました。 はい、ユーザープリンシパル名を承認および取得できますが、このユーザーに代わって何かを行う権限はありません。



次に、インターネット上で価値のあるものを見つけようとしました。 それらは比較的成功し、次のDjangoのパッケージが見つかりました: django-kerberosdjango-auth-spnegodjango-auth-kerbero 。 実際、これらのパッケージはすべて同じことを行い、一部は長時間更新されず、長時間「タンバリンと踊る」必要があったため、少なくとも何かが機能しました。 これらは、nginxバンドル(GSSAPI)+ Django(RemouteUser)と同じ機能を提供しました。 それらはすべて、ソースコードの問題を解決するのに役立ちました。



次に、PythonでGSSAPIを操作するための次のパッケージが見つかりました: ccs-pykerberosおよびpython-gssapi 、実際には、Pythonの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とbuildを使用してソースを複製する必要があります。



ブラウザはNegotiateを返すように設定する必要があります。デフォルトではこのオプションは無効になっています。 すべてのテストは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を開発したことを理解する上で多くを助けてくれました。



便利なリンク






All Articles