Recentemente, eu e meus colegas precisamos implementar uma autorização transparente (SSO) em nosso projeto. Agora, há bastante informação sobre o assunto, especialmente em russo. Por esse motivo, decidiu-se compartilhar com os descendentes a implementação dessa funcionalidade.
Portanto, a tarefa foi a seguinte: era necessário configurar a autorização transparente por meio do GSSAPI do usuário para o servidor e, em seguida, poder acessar o banco de dados em nome desse usuário.
Tivemos:
- servidor Kerberos + LDAP configurado
- Servidor PostgreSQL configurado para autorização exclusivamente pela GSSAPI
- Servidor de aplicativos Django + UWSGI + nginx com o Kerberos configurado
Inicialmente, a idéia era delegar a autorização do usuário no aplicativo para o servidor web, configurando a autorização GSSAPI nele e o Django para indicar que trabalharíamos com o RemoteUser. Como parte desta descrição, não falarei sobre como configurar o nginx para funcionar no GSSAPI e o Django para delegar autorização a um servidor da web. Esta é uma parte bem documentada e há muitos artigos sobre isso. Após o ajuste e os testes, percebemos que isso não é absolutamente o que precisamos. Sim, podemos autorizar e obter o nome principal do usuário, mas não temos direitos para fazer nada em nome desse usuário.
Depois, tentamos encontrar algo que valesse a pena na Internet. Eles foram relativamente bem-sucedidos e foram encontrados os seguintes pacotes para o Django:
django-kerberos ,
django-auth-spnego ,
django-auth-kerbero . De fato, todos esses pacotes fizeram a mesma coisa, alguns não foram atualizados por um longo tempo e tiveram que "dançar com um pandeiro" por um longo tempo, para que pelo menos alguma coisa funcionasse. Eles forneceram a mesma funcionalidade que o pacote nginx (GSSAPI) + Django (RemouteUser). Todos eles ajudaram a resolver o problema com o código fonte.
Em seguida, foram encontrados os seguintes pacotes para trabalhar com o GSSAPI no Python:
ccs-pykerberos e
python-gssapi ; na verdade, eles importam a implementação do padrão RFC2744 e RFC4559 no Python. Usando o pacote ccs-pykerberos, acabamos de implementar a funcionalidade pretendida; mostrarei um pequeno código em que a comunicação com o LDAP e o usuário é implementada, bem como uma consulta ao banco de dados em seu nome.
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)
Primeiro, precisamos verificar se o cabeçalho de autorização nos foi fornecido; caso contrário, devemos enviar o cabeçalho com Negociar em resposta e aguardar novamente o token do usuário Negociar. Esse token parece um grande calçado codificado em base64. Após receber o token, inicializamos (autorizamos) o servidor do nosso aplicativo no serviço LDAP usando a função authGSSServerInit (). Em seguida, autorizaremos no serviço LDAP em nome do usuário, usando a função authGSSServerStep () apenas para o token que foi recebido do cabeçalho. Em seguida, obtemos o principal do usuário, que usaremos como usuário, ao executar a consulta no banco de dados. Além disso, precisamos criar um cache de bits Kerberos, que será usado automaticamente para nos autorizar no PostgreSQL, a função authGSSServerStoreDelegate (). Esta função está disponível apenas na versão mais recente deste pacote, portanto você precisa clonar suas fontes com git e build.
O navegador deve estar configurado para retornar Negociar, por padrão esta opção está desabilitada. Todos os testes foram realizados no Firefox no CentOS7, e o CentOS7 foi instalado em todos os servidores.
Além disso, podemos ter um problema no qual o cache de tíquetes gerado por nossa função não estará visível para o nosso processo e, consequentemente, obteremos que o usuário não foi autorizado no GSSAPI. Isso é resolvido configurando o cache do ticket no krb5.conf. Apenas no caso, darei um exemplo de nossa configuração:
/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
Esse trecho de código foi criado para ajudar a entender como ocorrem a autorização e a delegação de direitos. Com esse conhecimento, você pode criar decoradores de autorização e backlinks de comunicação com o banco de dados. O pacote ccs-pykerberos foi desenvolvido pela Apple para suas necessidades internas, respectivamente, fornecerei um link para o código deles, onde eles o usam. Ele nos ajudou muito a entender que eles desenvolveram
ccs-calendarserver / twistedcaldav / authkerb.pyLinks úteis