OpenID Connect: autorización de aplicaciones internas de personalizadas a estándar

Hace unos meses, estaba implementando un servidor OpenID Connect para administrar el acceso a cientos de nuestras aplicaciones internas. A partir de desarrollos propios, convenientes a menor escala, hemos pasado a un estándar generalmente aceptado. El acceso a través del servicio central simplifica enormemente las operaciones monótonas, reduce el costo de implementación de las autorizaciones, le permite encontrar muchas soluciones listas para usar y no romperse los sesos al desarrollar otras nuevas. En este artículo, hablaré sobre esta transición y los baches que logramos llenar.

OpenID Connect: autorización de aplicaciones internas de personalizadas a estándar

Hace mucho tiempo... Cómo empezó todo

Hace unos años, cuando había demasiadas aplicaciones internas para el control manual, escribimos una aplicación para controlar el acceso dentro de la empresa. Era una sencilla aplicación Rails que se conectaba a una base de datos con información de los empleados, donde se configuraba el acceso a diversas funcionalidades. Al mismo tiempo, levantamos el primer SSO, que se basó en la verificación de tokens del lado del cliente y el servidor de autorización, el token se transmitió en forma encriptada con varios parámetros y se verificó en el servidor de autorización. Esta no era la opción más conveniente, ya que cada aplicación interna debía describir una capa de lógica considerable y las bases de datos de los empleados estaban completamente sincronizadas con el servidor de autorizaciones.

Después de un tiempo, decidimos simplificar la tarea de autorización centralizada. SSO se transfirió al equilibrador. Con la ayuda de OpenResty, se agregó una plantilla a Lua que verificaba los tokens, sabía a qué aplicación se dirigía la solicitud y podía verificar si había acceso allí. Este enfoque simplificó enormemente la tarea de controlar el acceso a las aplicaciones internas: en el código de cada aplicación, ya no era necesario describir una lógica adicional. Como resultado, cerramos el tráfico externamente y la aplicación en sí no sabía nada sobre la autorización.

Sin embargo, quedaba un problema sin resolver. ¿Qué pasa con las aplicaciones que necesitan información sobre los empleados? Era posible escribir una API para el servicio de autorización, pero luego tendría que agregar lógica adicional para cada una de esas aplicaciones. Además, queríamos deshacernos de la dependencia de una de nuestras aplicaciones escritas por nosotros mismos, que luego se traduciría a OpenSource, en nuestro servidor de autorización interno. Hablaremos de ello en otro momento. La solución a ambos problemas fue OAuth.

a los estándares comunes

OAuth es un estándar de autorización comprensible y generalmente aceptado, pero dado que su funcionalidad no es suficiente, inmediatamente comenzaron a considerar OpenID Connect (OIDC). OIDC en sí es la tercera implementación del estándar de autenticación abierta, que se convirtió en un complemento sobre el protocolo OAuth 2.0 (un protocolo de autorización abierta). Esta solución cierra el problema de la falta de datos sobre el usuario final y también permite cambiar el proveedor de autorización.

Sin embargo, no elegimos un proveedor específico y decidimos agregar la integración con OIDC para nuestro servidor de autorización existente. A favor de esta decisión estuvo el hecho de que OIDC es muy flexible en términos de autorización del usuario final. Por lo tanto, fue posible implementar la compatibilidad con OIDC en su servidor de autorización actual.

OpenID Connect: autorización de aplicaciones internas de personalizadas a estándar

Nuestra forma de implementar nuestro propio servidor OIDC

1) Trajo los datos a la forma deseada

Para integrar OIDC, es necesario llevar los datos del usuario actual a un formato comprensible para el estándar. En OIDC esto se llama Reclamos. Las reclamaciones son esencialmente campos finales en la base de datos del usuario (nombre, correo electrónico, teléfono, etc.). existe lista estándar de sellos, y todo lo que no está incluido en esta lista se considera personalizado. Por lo tanto, el primer punto al que debe prestar atención si desea elegir un proveedor de OIDC existente es la posibilidad de personalización conveniente de nuevas marcas.

El grupo de sellos se combina en el siguiente subconjunto: Alcance. Durante la autorización, no se solicita acceso a marcas específicas, sino a ámbitos, incluso si algunas de las marcas del ámbito no son necesarias.

2) Implementó las subvenciones necesarias

La siguiente parte de la integración de OIDC es la selección e implementación de tipos de autorización, las denominadas concesiones. El escenario adicional de interacción entre la aplicación seleccionada y el servidor de autorizaciones dependerá de la concesión seleccionada. En la siguiente figura se muestra un esquema ejemplar para elegir la subvención adecuada.

OpenID Connect: autorización de aplicaciones internas de personalizadas a estándar

Para nuestra primera aplicación, utilizamos la concesión más común, el Código de autorización. Su diferencia con los demás es que es de tres pasos, es decir. se está sometiendo a pruebas adicionales. Primero, el usuario realiza una solicitud de permiso de autorización, recibe un token - Código de autorización, luego, con este token, como si fuera un boleto para viajar, solicita un token de acceso. Toda la interacción principal de este script de autorización se basa en redireccionamientos entre la aplicación y el servidor de autorización. Puedes leer más sobre esta subvención aquí.

OAuth se adhiere al concepto de que los tokens de acceso obtenidos después de la autorización deben ser temporales y cambiar preferiblemente cada 10 minutos en promedio. La concesión del Código de autorización es una verificación de tres pasos a través de redireccionamientos, cada 10 minutos para convertir ese paso, francamente, no es la tarea más agradable para los ojos. Para resolver este problema, existe otra subvención: Refresh Token, que también usamos en nuestro país. Aquí todo es más fácil. Durante la verificación de otra concesión, además del token de acceso principal, se emite otro: Refresh Token, que se puede usar solo una vez y su vida útil suele ser mucho más larga. Con este Refresh Token, cuando finaliza el TTL (Time to Live) del token de acceso principal, la solicitud de un nuevo token de acceso llegará al punto final de otra concesión. El token de actualización usado se restablece inmediatamente a cero. Esta comprobación consta de dos pasos y se puede realizar en segundo plano, de forma imperceptible para el usuario.

3) Configurar formatos de salida de datos personalizados

Una vez que se implementan las concesiones seleccionadas, la autorización funciona, vale la pena mencionar la obtención de datos sobre el usuario final. OIDC tiene un punto final separado para esto, donde puede solicitar datos de usuario con su token de acceso actual y si está actualizado. Y si los datos del usuario no cambian con tanta frecuencia y necesita seguir los actuales muchas veces, puede llegar a una solución como los tokens JWT. Estos tokens también son compatibles con el estándar. El token JWT en sí consta de tres partes: encabezado (información sobre el token), carga útil (cualquier dato necesario) y firma (firma, el servidor firma el token y luego puede verificar la fuente de su firma).

En la implementación de OIDC, el token JWT se llama id_token. Se puede solicitar junto con un token de acceso normal y solo queda verificar la firma. El servidor de autorización tiene un punto final separado para esto con un montón de claves públicas en el formato J.W.K.. Y hablando de esto, vale la pena mencionar que hay otro punto final, que, basado en el estándar RFC5785 refleja la configuración actual del servidor OIDC. Contiene todas las direcciones de puntos finales (incluida la dirección del conjunto de claves públicas utilizadas para la firma), las marcas y los ámbitos compatibles, los algoritmos de cifrado utilizados, las concesiones compatibles, etc.

Por ejemplo en Google:

{
 "issuer": "https://accounts.google.com",
 "authorization_endpoint": "https://accounts.google.com/o/oauth2/v2/auth",
 "device_authorization_endpoint": "https://oauth2.googleapis.com/device/code",
 "token_endpoint": "https://oauth2.googleapis.com/token",
 "userinfo_endpoint": "https://openidconnect.googleapis.com/v1/userinfo",
 "revocation_endpoint": "https://oauth2.googleapis.com/revoke",
 "jwks_uri": "https://www.googleapis.com/oauth2/v3/certs",
 "response_types_supported": [
  "code",
  "token",
  "id_token",
  "code token",
  "code id_token",
  "token id_token",
  "code token id_token",
  "none"
 ],
 "subject_types_supported": [
  "public"
 ],
 "id_token_signing_alg_values_supported": [
  "RS256"
 ],
 "scopes_supported": [
  "openid",
  "email",
  "profile"
 ],
 "token_endpoint_auth_methods_supported": [
  "client_secret_post",
  "client_secret_basic"
 ],
 "claims_supported": [
  "aud",
  "email",
  "email_verified",
  "exp",
  "family_name",
  "given_name",
  "iat",
  "iss",
  "locale",
  "name",
  "picture",
  "sub"
 ],
 "code_challenge_methods_supported": [
  "plain",
  "S256"
 ],
 "grant_types_supported": [
  "authorization_code",
  "refresh_token",
  "urn:ietf:params:oauth:grant-type:device_code",
  "urn:ietf:params:oauth:grant-type:jwt-bearer"
 ]
}

Por lo tanto, al usar id_token, puede transferir todas las características necesarias a la carga útil del token y no contactar al servidor de autorización cada vez que solicite datos de usuario. La desventaja de este enfoque es que el cambio en los datos de usuario del servidor no se produce de inmediato, sino junto con un nuevo token de acceso.

Resultados de la implementación

Entonces, después de implementar nuestro propio servidor OIDC y configurar las conexiones en el lado de la aplicación, resolvimos el problema de transferir información sobre los usuarios.
Dado que OIDC es un estándar abierto, tenemos la opción de elegir un proveedor existente o una implementación de servidor. Probamos Keycloak, que resultó ser muy conveniente de configurar, después de configurar y cambiar las configuraciones de conexión en el lado de la aplicación, está listo para funcionar. Por el lado de la aplicación, todo lo que queda es cambiar las configuraciones de conexión.

Hablando de soluciones existentes

Dentro de nuestra organización, como el primer servidor OIDC, ensamblamos nuestra propia implementación, que se complementó según fue necesario. Después de una revisión detallada de otras soluciones preparadas, podemos decir que este es un punto discutible. A favor de la decisión de implementar un servidor propio, existían preocupaciones por parte de los proveedores ante la falta de la funcionalidad necesaria, así como la presencia de un sistema antiguo en el que existían diferentes autorizaciones personalizadas para algunos servicios y bastantes de datos sobre los empleados ya estaba almacenado. Sin embargo, en las implementaciones listas para usar, existen ventajas para la integración. Por ejemplo, Keycloak tiene su propio sistema de administración de usuarios y los datos se almacenan directamente en él, y no será difícil adelantar a sus usuarios allí. Para ello, Keycloak dispone de una API que te permitirá realizar íntegramente todas las acciones de transferencia necesarias.

Otro ejemplo de una implementación certificada, interesante, en mi opinión, es Ory Hydra. Es interesante porque consta de diferentes componentes. Para realizar la integración, deberá vincular su servicio de administración de usuarios a su servicio de autorización y ampliarlo según sea necesario.

Keycloak y Ory Hydra no son las únicas soluciones listas para usar. Lo mejor es elegir una implementación certificada por OpenID Foundation. Estas soluciones suelen tener una insignia de certificación OpenID.

OpenID Connect: autorización de aplicaciones internas de personalizadas a estándar

Además, no se olvide de los proveedores de pago existentes si no desea mantener su servidor OIDC. Hoy en día hay muchas buenas opciones.

¿Qué sigue

En un futuro cercano, vamos a cerrar el tráfico a los servicios internos de una manera diferente. Planeamos transferir nuestro SSO actual en el balanceador usando OpenResty a un proxy basado en OAuth. Ya hay muchas soluciones preparadas aquí, por ejemplo:
github.com/bitly/oauth2_proxy
github.com/ory/oathkeeper
github.com/keycloak/keycloak-gatekeeper

Materiales adicionales

jwt.io – buen servicio para validar tokens JWT
openid.net/desarrolladores/certificado - lista de implementaciones OIDC certificadas

Fuente: habr.com

Añadir un comentario