OpenID Connect : autorisation des applications internes du custom au standard

Il y a quelques mois, j'implémentais un serveur OpenID Connect pour gérer l'accès à des centaines de nos applications internes. De nos propres développements, pratiques à plus petite échelle, nous sommes passés à une norme généralement acceptée. L'accès via le service central simplifie grandement les opérations monotones, réduit le coût de mise en œuvre des autorisations, vous permet de trouver de nombreuses solutions toutes faites et de ne pas vous casser la tête lors du développement de nouvelles. Dans cet article, je parlerai de cette transition et des bosses que nous avons réussi à combler.

OpenID Connect : autorisation des applications internes du custom au standard

Il y a longtemps... comment tout a commencé

Il y a quelques années, alors qu'il y avait trop d'applications internes de contrôle manuel, nous avons écrit une application pour contrôler les accès au sein de l'entreprise. Il s'agissait d'une simple application Rails qui se connectait à une base de données contenant des informations sur les employés, où l'accès à diverses fonctionnalités était configuré. Dans le même temps, nous avons levé le premier SSO, qui était basé sur la vérification des jetons du côté du client et du serveur d'autorisation, le jeton était transmis sous forme cryptée avec plusieurs paramètres et vérifié sur le serveur d'autorisation. Ce n'était pas l'option la plus pratique, car chaque application interne devait décrire une couche logique considérable et les bases de données des employés étaient complètement synchronisées avec le serveur d'autorisation.

Après un certain temps, nous avons décidé de simplifier la tâche d'autorisation centralisée. SSO a été transféré à l'équilibreur. Avec l'aide d'OpenResty, un modèle a été ajouté à Lua qui vérifiait les jetons, savait à quelle application la requête allait et pouvait vérifier s'il y avait un accès là-bas. Cette approche simplifiait grandement la tâche de contrôle d'accès aux applications internes - dans le code de chaque application, il n'était plus nécessaire de décrire une logique supplémentaire. En conséquence, nous avons fermé le trafic en externe et l'application elle-même ne savait rien de l'autorisation.

Cependant, un problème restait en suspens. Qu'en est-il des applications qui ont besoin d'informations sur les employés ? Il était possible d'écrire une API pour le service d'autorisation, mais il faudrait alors ajouter une logique supplémentaire pour chacune de ces applications. De plus, nous voulions nous débarrasser de la dépendance vis-à-vis d'une de nos applications auto-écrites, orientée à l'avenir pour la traduction en OpenSource, vis-à-vis de notre serveur d'autorisation interne. Nous en reparlerons une autre fois. La solution aux deux problèmes était OAuth.

aux normes communes

OAuth est une norme d'autorisation compréhensible et généralement acceptée, mais comme seule sa fonctionnalité ne suffit pas, ils ont immédiatement commencé à envisager OpenID Connect (OIDC). OIDC lui-même est la troisième implémentation de la norme d'authentification ouverte, qui s'est transformée en un module complémentaire sur le protocole OAuth 2.0 (un protocole d'autorisation ouvert). Cette solution résout le problème du manque de données sur l'utilisateur final, et permet également de changer de fournisseur d'autorisation.

Cependant, nous n'avons pas choisi de fournisseur spécifique et avons décidé d'ajouter l'intégration avec OIDC pour notre serveur d'autorisation existant. Cette décision a été favorisée par le fait que l'OIDC est très flexible en termes d'autorisation de l'utilisateur final. Ainsi, il a été possible d'implémenter le support OIDC sur votre serveur d'autorisation actuel.

OpenID Connect : autorisation des applications internes du custom au standard

Notre façon d'implémenter notre propre serveur OIDC

1) A apporté les données à la forme souhaitée

Pour intégrer OIDC, il est nécessaire de mettre les données utilisateur actuelles sous une forme compréhensible par la norme. Dans OIDC, cela s'appelle Revendications. Les réclamations sont essentiellement des champs finaux dans la base de données des utilisateurs (nom, e-mail, téléphone, etc.). Existe liste standard des timbres, et tout ce qui n'est pas inclus dans cette liste est considéré comme personnalisé. Par conséquent, le premier point auquel vous devez faire attention si vous souhaitez choisir un fournisseur OIDC existant est la possibilité de personnaliser facilement les nouvelles marques.

Le groupe de poinçons est combiné dans le sous-ensemble suivant - Champ d'application. Lors de l'autorisation, l'accès n'est pas demandé à des marques spécifiques, mais à des périmètres, même si certaines des marques du périmètre ne sont pas nécessaires.

2) Mise en place des subventions nécessaires

La partie suivante de l'intégration OIDC est la sélection et la mise en œuvre des types d'autorisation, les soi-disant subventions. L'autre scénario d'interaction entre l'application sélectionnée et le serveur d'autorisation dépendra de la subvention sélectionnée. Un schéma exemplaire pour choisir la bonne subvention est illustré dans la figure ci-dessous.

OpenID Connect : autorisation des applications internes du custom au standard

Pour notre première application, nous avons utilisé la subvention la plus courante, le code d'autorisation. Sa différence avec les autres est qu'il s'agit d'un processus en trois étapes, c'est-à-dire subit des tests supplémentaires. Tout d'abord, l'utilisateur fait une demande d'autorisation, reçoit un jeton - Code d'autorisation, puis avec ce jeton, comme s'il s'agissait d'un billet de voyage, demande un jeton d'accès. Toute l'interaction principale de ce script d'autorisation est basée sur des redirections entre l'application et le serveur d'autorisation. Vous pouvez en savoir plus sur cette subvention ici.

OAuth adhère au concept selon lequel les jetons d'accès obtenus après autorisation doivent être temporaires et changer de préférence toutes les 10 minutes en moyenne. L'octroi du code d'autorisation est une vérification en trois étapes via des redirections, toutes les 10 minutes pour tourner une telle étape, franchement, n'est pas la tâche la plus agréable pour les yeux. Pour résoudre ce problème, il existe une autre subvention - Refresh Token, que nous avons également utilisée dans notre pays. Tout est plus facile ici. Lors de la vérification à partir d'une autre autorisation, en plus du jeton d'accès principal, un autre est émis - le jeton d'actualisation, qui ne peut être utilisé qu'une seule fois et sa durée de vie est généralement beaucoup plus longue. Avec ce jeton d'actualisation, lorsque le TTL (Time to Live) du jeton d'accès principal se termine, la demande d'un nouveau jeton d'accès arrivera au point de terminaison d'une autre autorisation. Le jeton de rafraîchissement utilisé est immédiatement remis à zéro. Cette vérification est en deux étapes et peut être effectuée en arrière-plan, de manière imperceptible pour l'utilisateur.

3) Configurer des formats de sortie de données personnalisés

Une fois les subventions sélectionnées mises en œuvre, l'autorisation fonctionne, il convient de mentionner l'obtention de données sur l'utilisateur final. OIDC a un point de terminaison distinct pour cela, où vous pouvez demander des données utilisateur avec votre jeton d'accès actuel et s'il est à jour. Et si les données de l'utilisateur ne changent pas si souvent et que vous devez suivre les données actuelles plusieurs fois, vous pouvez trouver une solution telle que les jetons JWT. Ces jetons sont également pris en charge par la norme. Le jeton JWT lui-même se compose de trois parties : en-tête (informations sur le jeton), charge utile (toutes les données nécessaires) et signature (signature, le jeton est signé par le serveur et vous pouvez vérifier ultérieurement la source de sa signature).

Dans l'implémentation OIDC, le jeton JWT est appelé id_token. Il peut être demandé avec un jeton d'accès régulier et il ne reste plus qu'à vérifier la signature. Le serveur d'autorisation a un point de terminaison séparé pour cela avec un groupe de clés publiques au format Ctte. Et en parlant de cela, il convient de mentionner qu'il existe un autre point final qui, sur la base de la norme RFC5785 reflète la configuration actuelle du serveur OIDC. Il contient toutes les adresses de point de terminaison (y compris l'adresse du trousseau de clés publiques utilisé pour la signature), les marques et étendues prises en charge, les algorithmes de chiffrement utilisés, les octrois pris en charge, etc.

Par exemple sur 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"
 ]
}

Ainsi, en utilisant id_token, vous pouvez transférer toutes les caractéristiques nécessaires à la charge utile du jeton et ne pas contacter le serveur d'autorisation à chaque fois pour demander des données utilisateur. L'inconvénient de cette approche est que la modification des données utilisateur du serveur ne se produit pas immédiatement, mais avec un nouveau jeton d'accès.

Résultats de la mise en œuvre

Ainsi, après avoir implémenté notre propre serveur OIDC et configuré les connexions à celui-ci du côté de l'application, nous avons résolu le problème du transfert d'informations sur les utilisateurs.
OIDC étant une norme ouverte, nous avons la possibilité de choisir un fournisseur existant ou une implémentation de serveur. Nous avons essayé Keycloak, qui s'est avéré très pratique à configurer, après avoir configuré et modifié les configurations de connexion côté application, il est prêt à fonctionner. Côté application, il ne reste plus qu'à modifier les configurations de connexion.

Parler des solutions existantes

Au sein de notre organisation, en tant que premier serveur OIDC, nous avons assemblé notre propre implémentation, qui a été complétée si nécessaire. Après un examen détaillé d'autres solutions toutes faites, nous pouvons dire que c'est un point discutable. En faveur de la décision de mettre en œuvre leur propre serveur, les fournisseurs s'inquiétaient de l'absence des fonctionnalités nécessaires, ainsi que de la présence d'un ancien système dans lequel il existait différentes autorisations personnalisées pour certains services et beaucoup des données sur les employés étaient déjà stockées. Cependant, dans les implémentations prêtes à l'emploi, il existe des commodités pour l'intégration. Par exemple, Keycloak possède son propre système de gestion des utilisateurs et les données y sont stockées directement, et il ne sera pas difficile d'y dépasser vos utilisateurs. Pour ce faire, Keycloak dispose d'une API qui vous permettra de réaliser intégralement toutes les actions de transfert nécessaires.

Un autre exemple d'une implémentation certifiée, intéressante, à mon avis, est Ory Hydra. Il est intéressant car il se compose de différents composants. Pour l'intégrer, vous devrez lier votre service de gestion des utilisateurs à leur service d'autorisation et étendre au besoin.

Keycloak et Ory Hydra ne sont pas les seules solutions prêtes à l'emploi. Il est préférable de choisir une implémentation certifiée par l'OpenID Foundation. Ces solutions ont généralement un badge de certification OpenID.

OpenID Connect : autorisation des applications internes du custom au standard

N'oubliez pas non plus les fournisseurs payants existants si vous ne souhaitez pas conserver votre serveur OIDC. Aujourd'hui, il existe de nombreuses bonnes options.

Quelle est la prochaine

Dans un avenir proche, nous allons fermer le trafic vers les services internes d'une manière différente. Nous prévoyons de transférer notre SSO actuel sur l'équilibreur utilisant OpenResty vers un proxy basé sur OAuth. Il existe déjà de nombreuses solutions toutes faites ici, par exemple :
github.com/bitly/oauth2_proxy
github.com/ory/oathkeeper
github.com/keycloak/keycloak-gatekeeper

Matériaux supplémentaires

jwt.io – bon service pour valider les jetons JWT
openid.net/developers/certified - liste des implémentations OIDC certifiées

Source: habr.com

Ajouter un commentaire