django запросить перенос в пользовательскую базу данных
Моя команда разрабатывает защищенный проект django, и мы добавили запрос Django в пользовательский сервер базы данных.
Мы создали такой алгоритм для аутентификации GSSAPI(SPNEGO) в django и делегирования учетных данных пользователя для запросов к серверу от имени пользователя:
if 'HTTP_AUTHORIZATION' in request.META:
kind, initial_client_token = request.META['HTTP_AUTHORIZATION'].split(' ', 1)
if kind == 'Negotiate':
server = 'HTTP@server.domain.ru'
_ignore_result, krb_context = kerberos.authGSSServerInit(server)
kerberos.authGSSServerStep(krb_context, initial_client_token)
principal = kerberos.authGSSServerUserName(krb_context)
_ignore_result = kerberos.authGSSServerStoreDelegate(krb_context)
conn = psycopg2.connect(
host='krb5-dbhost',
user=principal,
dbname='db',
)
cursor = conn.cursor()
cursor.execute("SELECT version()")
records = cursor.fetchall()
это хорошо работает в django-view. Сервер Kerberos может авторизовать пользователя и кеш-билет krb5 для делегирования полномочий для запроса в psycopg. Теперь нам нужно ввести его в Джанго.
Мы хотим, чтобы наследовать базу данных postgresql, как это:
from django.db.backends.postgresql_psycopg2.base import DatabaseWrapper
class CustomDatabaseWrapper(DatabaseWrapper):
def __init__(self, *args, **kwargs):
super(CustomDatabaseWrapper, self).__init__(*args, **kwargs)
def get_connection_params(self):
'''We need to customize this function,
We need get request here when query processed by web interface,'''
#.... the source code could be here, but it is not necessary
return conn_params
Поэтому возникает вопрос: "Как мы можем получить request.META (для получения токена Negotiate пользователя) в функции get_connection_params(), и как мы можем отделить пользовательский запрос от веб-интерфейса от команд управления".
Извините за мои навыки английского языка. Спасибо!
1 ответ
Здесь есть промежуточное ПО и база данных, для кеша используется https://github.com/kogan/django-lrucache-backend
from django.http import HttpResponse
from django.core.cache import caches
from django.conf import settings
import kerberos
import os
class GSSAPIMiddleware(object):
"""GSSAPI Middleware make user auth and cache user token
and user name. Needed to fix gssstring response like
spnego protocol says to return response with this string"""
def process_view(self, request, *args, **kwargs):
if not settings.GSSAPI_ENABLED_OPTION:
return None
unauthorized = False
if 'HTTP_AUTHORIZATION' in request.META:
kind, initial_client_token = request.META['HTTP_AUTHORIZATION'].split(' ', 1)
if kind == 'Negotiate':
local = caches['local']
server = settings.GSSAPI_SERVER
os.environ['KRB5_KTNAME'] = settings.GSSAPI_KEYTAB_PATH
result, krb_context = kerberos.authGSSServerInit(server)
kerberos.authGSSServerStep(krb_context, initial_client_token)
# gssstring = kerberos.authGSSServerResponse(krb_context) FIXME
principal = kerberos.authGSSServerUserName(krb_context)
_ignore_result = kerberos.authGSSServerStoreDelegate(krb_context)
local.set(settings.GSSAPI_USER_PRINCIPAL_KEY, principal)
else:
unauthorized = True
else:
unauthorized = True
if unauthorized:
return HttpResponse('Unauthorized', status=401)
return None
def process_request(self, request, *args, **kwargs):
"""function call for every view before Django
choose witch view would be called. function
ask user`s browser for Negotiate token"""
if not settings.GSSAPI_ENABLED_OPTION:
return None
unauthorized = False
if 'HTTP_AUTHORIZATION' in request.META:
kind, initial_client_token = request.META['HTTP_AUTHORIZATION'].split(' ', 1)
if kind != 'Negotiate':
unauthorized = True
else:
unauthorized = True
if unauthorized:
response = HttpResponse(request, status=401)
response['WWW-Authenticate'] = 'Negotiate'
return response
return None
и база данных для postgresql
from django.db.backends.postgresql_psycopg2.base import DatabaseWrapper as DaWr
from django.core.cache import caches
from django.conf import settings
class DatabaseWrapper(DaWr):
"""Custom database backend version for GSSAPI auth
get user creds from Kerberos and get ticket"""
def __init__(self, *args, **kwargs):
super(DatabaseWrapper, self).__init__(*args, **kwargs)
def get_connection_params(self):
conn_params = super(DatabaseWrapper, self).get_connection_params()
if settings.GSSAPI_ENABLED_OPTION:
local = caches['local']
principal = local.get(settings.GSSAPI_USER_PRINCIPAL_KEY)
conn_params['user'] = principal
return conn_params