django запросить перенос в пользовательскую базу данных - PullRequest
0 голосов
/ 25 октября 2018

Моя команда разрабатывает защищенный проект 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.Теперь нам нужно внедрить его в django.

Мы хотим, чтобы наследовать базу данных 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 (для полученияпользовательский токен согласования) в функции get_connection_params () и как мы можем отделить пользовательский запрос от веб-интерфейса от команд управления. "

Извините за мои навыки английского языка. Спасибо!

1 Ответ

0 голосов
/ 30 октября 2018

это промежуточное ПО и серверная часть базы данных, для кеша используется 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
...