Авторизация пользователей в Django через GSSAPI и делегация прав пользователя серверу

от автора

Недавно нам с коллегами понадобилось реализовать прозрачную (SSO) авторизацию в нашем проекте. Сейчас довольно мало информации по теме особенно на русском языке. По этой причине решено было поделиться с потомками реализацией подобного функционала.

Итак задача заключалась в следующем: необходимо было настроить прозрачную авторизацию через GSSAPI от пользователя на сервер, а так же иметь потом возможность от имени этого пользователя ходить в БД.

У нас имелось:

  • настроенный сервер Kerberos+LDAP
  • сервер PostgreSQL, настроенный на авторизацию исключительно по GSSAPI
  • сервер приложения Django+UWSGI+nginx, с настроенным Kerberos

Изначально была идея делегировать авторизацию пользователей в приложении веб серверу, настроив на нем авторизацию по GSSAPI, а Django указать, что мы будем работать с RemoteUser. В рамках данного описания, я не буду рассказывать, как настроить nginx на работу по GSSAPI, а Django на делегацию авторизации на веб сервер, это хорошо задокументированная часть, да и статей по этому поводу довольно много. После настройки и проведенных тестов — мы поняли, что это абсолютно не то, что нам нужно. Да мы можем провести авторизацию и получить user principal name, но мы не имеем прав от имени этого пользователя ничего сделать.

Далее нами были предприняты попытки найти что-то стоящее на просторах интернета. Они увенчались относительным успехом, были найдены следующие пакеты для Django: django-kerberos, django-auth-spnego, django-auth-kerbero. По сути все эти пакеты делали одно и тоже, некоторые не обновлялись уже давно и пришлось долго «танцевать с бубном», что бы хоть что то заработало. Они предоставляли такой же функционал как и связка nginx(GSSAPI)+Django(RemouteUser). Все они помогли прийти к решению проблемы своим исходным кодом.

Далее были найдены следующие пакеты для работы с GSSAPI в Python: ccs-pykerberos и python-gssapi, по сути они импортируют реализацию стандарта RFC2744 и RFC4559 в Python. С помощью пакета 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. После получения токена, мы инициализируем (авторизуем) сервер нашего приложения в LDAP сервисе, используя функцию authGSSServerInit(). Далее мы авторизуемся в LDAP сервисе от имени пользователя, используя для этого как раз тот токен, который получили из заголовка, функция authGSSServerStep(). Потом мы получаем principal пользователя, который будем использовать в качестве user, при выполнении запроса в БД. А так же, нам необходимо сформировать кэш битела Kerberos, который будет использован автоматически для того, что бы авторизовать нас в PostgreSQL, функция authGSSServerStoreDelegate(). Данная функция есть только в самой последней версии этого пакета, поэтому нужно клонировать себе исходники с git и сделать build.

Браузер должен быть настроен на отдачу Negotiate, по умолчанию эта опция отключена. Все тесты проводились на Firefox в CentOS7, так же на всех серверах был установлен 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

Полезные ссылки


ссылка на оригинал статьи https://habr.com/post/427839/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *