Em um projeto novo da SIGMA, nos foi solicitado que utilizássemos
os usuários registrados no Active Directory do cliente, significando
que teríamos de integrar toda a funcionalidade de login do nosso projeto
Django com este camarada.

Existem diversas razões para esta integração, principalmente no nosso
caso, em que o cliente final é uma grande empresa, com toda uma infraestrutura
de Tecnologia da Informação bastante sólida e madura.

Entre estas razões, se encontram, em ordem de prioridade:

  1. Cliente não quer mais um usuário/senha para usar um sistema especialista;
  2. Equipe de TI não quer gerenciar os cadastros dos usuários em mais um sistema;
  3. Economia no desenvolvimento, de tempo e dinheiro;

Como funciona?

O Django, como um framework, já possui toda um maquinário importante para
criação e manutenção de permissões e grupos. Mas existe uma "pegadinha":
o usuário em questão precisa existir no banco de dados que estamos usando.

Isto porque as permissões e grupos estão armazenadas em um banco de dados
relacional e existem relações com chaves estrangeiras entre usuários, permissões
e grupos.

O fluxo mais simples, portanto é:

  1. Usuário se autentica com a senha do Active Directory;
  2. Usuário está inativo no AD? Caso esteja, impeça o login e inative o usuário local;
  3. Usuário não está inativo, confira a senha;
  4. Sistema confere se o usuário já existe na base local;
  5. Caso ele já exista, ok, não faça mais nada;
  6. Caso ele não exista, copie os dados do usuário e crie um novo usuário na base local;
  7. Associe permissões/grupos;
  8. Vitória;

Seguindo este fluxo, todos os componentes do Django continuam a funcionar e não
precisamos criar permissões remotas no AD (ou LDAP) o que tornaria tudo
mais complicado de administrar (pense nas migrações do Django).

Outro ponto importante, delimitador deste fluxo, é a necessidade das sessões HTTP
no Django. Sem existir um usuário na base, não conseguiremos manter as sessões. Teríamos
de adaptar também o componente que registra e valida as sessões ativas.

Portanto esta arquitetura de cópia de usuários é a mais comum para integração
em bases de usuários "remotas" (este fluxo também é usado em pacotes que realizam
autenticação e integração com outros provedores de login, como OAuth2, por exemplo).

Como realizar a integração?

Felizmente, o Django é um projeto bastante modular. Neste caso em específico,
o Django aceita a configuração de settings de autenticação, permitindo
inclusive a autenticação em múltiplos backends, em cascata. Caso a autenticação
do usuário não funcione em um backend, ele tenta no próximo.

A arquitetura do Django facilitou bastante nossa vida neste sentido.

Quais são os passos:

Configurar o AUTHENTICATION_BACKENDS em seus settings.py

Desenvolver ou reutilizar um pacote open-source que já faz a conexão
e validação do usuário no Active Directory. No nosso caso, utilizamos o
django-python3-ldap.

Configurar as variáveis do django-python3-ldap:

# settings.py
LDAP_AUTH_USER_FIELDS = {
  "username": "uid",
  "first_name": "givenName",
  "last_name": "sn",
  "email": "mail",
}
LDAP_AUTH_USER_LOOKUP_FIELDS = ("username",)
LDAP_AUTH_CLEAN_USER_DATA = "django_python3_ldap.utils.clean_user_data"
LDAP_AUTH_SYNC_USER_RELATIONS = "jango_python3_ldap.utils.sync_user_relation"
"  LDAP_AUTH_FORMAT_SEARCH_FILTERS = "django_python3_ldap.utils.format_search_filters"
# Atenção neste ponto, pois ele é necessário para funcionar com o AD
LDAP_AUTH_FORMAT_USERNAME = "django_python3_ldap.utils.format_username_active_directory"```

Para a url indique conforme abaixo substituindo <ip_ou_dominio>
por seu ip ou dominio:

# settings.py
LDAP_AUTH_URL='ldap://<ip_ou_dominio>:389'

Utilize o comando dsquery user no ms-dos para obter a seguinte informação informação:

C:\Users\csantos>dsquery user
"CN=Claudio Santos,CN=Users,DC=server,DC=local"
"CN=Guest,CN=Users,DC=server,DC=local"

Utilize os três critérios de pesquisa, resultando em: LDAP_AUTH_SEARCH_BASE = 'CN=Users,DC=server,DC=local'

Comumente temos dois tipos de usuários: InetOrgPerson ou Users. Nós utilizamos o Users,
configurando LDAP_AUTH_OBJECT_CLASS = 'Users'

Configure este settings com uma variável que podemos pegar na
tela de criação de usuário no campo em destaque na imagem,
ela representa o Pre-Windows 2000 Domain Name do Active Directory:

attribute-editor-uid

# settings.py
LDAP_AUTH_ACTIVE_DIRECTORY_DOMAIN = 'SERVER'

Por fim vá em Active Directory Users and Computer, vá na pasta Users,
em seguida, clique com o botão direito, propriedades e por fim na aba Atributte Editor
informe o login do usuário no atributo uid, como mostrado na imagem abaixo;

attribute-editor-uid

Conclusões

Não vou discorrer aqui sobre os benefícios técnicos de usar open-source ou
coisa do tipo, mas sim dos benefícios gerados por uma integração deste nível.

As vantagens auferidas tem um profundo impacto psicológico sobre o usuário final
e sobre o retorno sobre investimento.

Em primeiro lugar, o sistema parece ter sido construído e fazer parte de fato
de toda a organização. O usuário não tem a impressão de sair de seu ambiente tecnológico,
confortável e seguro, para trabalhar em um sistema externo.

Como segundo ponto, o usuário tem uma barreira menor para utilizar o sistema.
A adoção de novos sistemas em organizações grandes sempre foi e sempre será
uma dificuldade, pelo próprio fator humano. Como a barreria de início é menor,
maior será a adoção dos usuários.

Em terceiro lugar, mas consequência do segundo ponto, quanto maior a adoção
dos usuários, maior o impacto que o novo sistema terá na organização, trazendo
um retorno maior para os stakeholders do projeto.