sábado, 29 de agosto de 2020

Autentificación de usuarios en Django contra el Servidor OpenID Keycloak con la ayuda de django-allauth

Las presentaciones

Entiendo que si has llegado aquí es por que conoces de sobra Django y probablemente te hayas topado con Keycloak.

Particularmente di con Keycloak buscando una solución que me pudiera simplificar la vida con la gestión de usuarios de una aplicación web corporativa. A la que quería dar acceso a todos los usuarios registrados en el Active Directory, junto con otros usuarios que se debían gestiona a parte.

Ademas quería contar con un mecanismo de Single Sign On para poder huir de crear grandes aplicaciones corporativas monolíticas y poder hacer Apps más especializadas sin que los usuarios tuvieran que ir introduciendo su usuario y contraseña cada vez que cambian de Aplicación / Funcionalidad.

Docker Keycloack 

Para ejecutar Keycloak en Docker, crea un archivo keycloak-postgresql.yml con el siguiente contenido:


version: '3'

volumes:
  postgres_data:
      driver: local

services:
  postgres:
      image: postgres
      volumes:
        - postgres_data:/var/lib/postgresql/data
      environment:
        POSTGRES_DB: keycloak
        POSTGRES_USER: keycloak
        POSTGRES_PASSWORD: password
  keycloak:
      image: quay.io/keycloak/keycloak:latest
      environment:
        DB_VENDOR: POSTGRES
        DB_ADDR: postgres
        DB_DATABASE: keycloak
        DB_USER: keycloak
        DB_SCHEMA: public
        DB_PASSWORD: password
        KEYCLOAK_USER: admin
        KEYCLOAK_PASSWORD: Pa55w0rd
        # Uncomment the line below if you want to specify JDBC parameters. The parameter below is just an example, and it shouldn't be used in production without knowledge. It is highly recommended that you read the PostgreSQL JDBC driver documentation in order to use it.
        #JDBC_PARAMS: "ssl=true"
      ports:
        - 8080:8080
      depends_on:
        - postgres
        

Para ejecutarlo:


  $ docker-compose -f keycloak-postgresql.yml up -d --build

Una vez ejecutado el comando y habiéndose puesto en marcha correctamente, deberemos poder acceder a la página de administración de Keycloak:

http://localhost:8080/auth/

Entra en la opción Administration Console y haz el login con admin y Pa55w0rd como se predefinió en keycloak-postgresql.ym.

Crea tu Reino en Keycloak

Pulsa sobre el desplegable Master y posteriormente sobre la opción "Add realm"

Como Name djangotest y guardamos

Estando dentro del reino djangotest crea por lo menos un usuario, mediante la opción Manage -> Users -> Add user

Yo me he creado el usuario demouser y posteriormente le he asignado una contraseña en la pestaña Credentials que he dejado marcada como Temporary para que me obligue a modificarla la primera vez que haga el login con ese usuario.

Dar acceso al proyecto Django como "cliente"

Hay que autorizar a nuestra aplicación para que pueda "consumir" credenciales proporcionadas por Keycloak, por lo que dentro de la sección Clients pulsaremos en Create.

Para el ejemplo podemos utilizar djangoclient y pulsamos en Save.

En la pestaña de Settings tenemos que configurar que URLs permitimos que el cliente solicite a Keycloak que sea redirigido el usuario una vez que se ha hecho el Login correctamente. Para el ejemplo ya que correremos el proyecto de Django también en local utilizaremos http://localhost:8000/*

Crear el proyecto Django


> mkdir djangoclient
> cd djangoclient
> virtualenv env
(env) > .\env\Scripts\activate
(env) > pip install django
(env) > pip install django-allauth
# Por costumbre siempre llamo a la aplicacion APP de forma
# que dentro de la carpeta con el nombre de la aplicación 
# me queda una carpeta env para el entorno 
# y otra app donde está el código fuente
(env) > django-admin startproject app 
(env) > cd app

Editar el archivo app\settings.py


INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',

    # Añadido para allauth
    'django.contrib.sites',

    'allauth',
    'allauth.account',
    'allauth.socialaccount',
    'allauth.socialaccount.providers.keycloak',
]

# Añadido para allauth
SOCIALACCOUNT_PROVIDERS = {
    'keycloak': {
        'KEYCLOAK_URL': 'http://localhost:8080/auth', # Servidor Keycloak
        'KEYCLOAK_REALM': 'Djangotest' # Nombre del Reino
    }
}

# Añadido para allauth
AUTHENTICATION_BACKENDS = (
    # Needed to login by username in Django admin, regardless of `allauth`
    'django.contrib.auth.backends.ModelBackend',
    # `allauth` specific authentication methods, such as login by e-mail
    'allauth.account.auth_backends.AuthenticationBackend',
)

# Añadido para allauth
SITE_ID = 1

# It's important that the domain follows the RFC 1034/1035 or else Django will complain
# This URL is defined as an extra host in client/docker-compose.yml
# We use the exposed port and not the host port because this URL will be fetched programmatically by the container
OAUTH_SERVER_BASEURL = 'http://localhost:8080'

Editar el archivo app\urls.py


from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('accounts/', include('allauth.urls')),
]

Ejecutamos la migración para que se adecue la BBDD


(env) > py manage.py migrate
(env) > py manage.py createsuperuser
(env) > py manage.py runserver

Entrar en http://localhost:8000/admin para crear una nueva entrada en Social applications.

Selecciona como Provider: Keycloak, en Name: keycloak y como Client id: djangoclient, que es el nombre que diste en Keycloak para la aplicación cliente. Añade a Chosen sites: example.com.

Añade un Site, es obligatorio pero creo que es parte de la funcionalidad de Allauth como gestor de usuarios y no es algo que tenga relevancia en la autentificación a través de Keycloak.

Login a través de Keycloak

Ha llegado el momento de probar que funciona

Como no tenemos preparada ninguna vista y ver errores nos podría despistar, lo que vamos a hacer es intentar modificar directamente el eMail y como no estamos "logeados" nos desviará al formulario de login. Si al introducir el usuario y la contraseña correctos nos lleva a la página de actualización del email significará que lo tenemos funcionando.

Entra en http://localhost:8000/accounts/email/, observa que nos ha llevado a la vista /accounts/login/.

Pulsa sobre Keycloak y deberemos ser llevados al login de Keycloak en el reino DJANGOTEST.

Introduce el usuario demouser que creamos al principio y si todo ha ido como se esperaba llegarás a la vista que te permite modificar el email.

Documentación de django-allauth