05 January 2016

Connexion OAuth et synchronisation des données avec RabbitMQ

La société Quovadis, cliente de l’agence AppVentus, souhaite offrir une expérience digitale globale à ses internautes. C’est dans cette optique que nous avons mis en place une application centralisée d’authentification et de synchronisation des données utilisateur. À terme, avec un même compte, un utilisateur pourra se connecter sur les sites quovadis.eu, store.quovadis.eu, quovadis.eu/pro et disposera des mêmes données sur chacune de ces plateformes.

Le projet a débuté par une phase de recherche des solutions existantes. Nous nous sommes notamment arrêtés sur la solution CAS (Central Authentication Service) JASIG mais celle-ci ne répondait pas à tous nos besoins : impossibilité pour les utilisateurs de gérer les sites sur lesquels ils souhaitent être authentifiés, difficultés à centraliser l’inscription et la gestion du profil, etc. De plus les documentations proposées pour JASIG et toutes les autres solutions CAS que nous avons étudiées nous paraissaient trop abstraites et nous imposaient un temps d’apprentissage trop important.

Nous avons donc décidé de développer notre propre solution comprenant :

Technos utilisées

Deux technologies principale composent ce projet :

  • OAuth2 : vous pouvez lire ce très bon article de Johann Reinke pour comprendre le fonctionnement d’OAuth2.
  • RabbitMQ : nous vous conseillons de lire les 6 tutoriels proposés sur le site officiel; ces articles donnent un bon aperçu de l’éventail des fonctionnalités proposées par cette application.

Fonctionnement

Chaque site Quovadis dispose de son propre compte utilisateur. Le compte utilisateur centralisé (OpenID) est utilisé pour l’authentification, la synchronisation des données facultatives et la synchronisation de la seule donnée obligatoire : l’adresse mail. Le mot de passe n’est stocké que sur le compte Quovadis OpenID : comme pour une connexion Facebook OpenID, un identifiant unique sera stocké sur chaque site Quovadis mais jamais le mot de passe.

OAuth2

Les sites Quovadis peuvent proposer plusieurs types de connexion : Quovadis, Facebook, Twitter et Linkedin. Lorsque l’utilisateur choisit l’un de ces modes de connexion, il est redirigé vers Quovadis Connect. Dans le cas d’une connexion Quovadis, il est invité à saisir ses identifiants ou s’enregistrer, sinon il est redirigé de manière transparente vers le service tiers de connexion demandé et repassera par Quovadis Connect pour y créer une session.

Workflow

Workflow OAuth2 Quovadis
  1. Si l’utilisateur souhaite accéder à une url sous le firewall d’une application client et qu’il n’a pas de session active, HWIBundle le redirige automatiquement vers l’url d’authentification du serveur OAuth : /oauth/v2/auth.
  2. Si l’utilisateur ne dispose pas de session active du côté serveur, il sera redirigé vers le formulaire de login de Quovadis Connect : /oauth/v2/login. Après création de la session, le serveur le redirigera vers le client avec un code.
  3. Puis le client, via HWIBundle, interrogera à nouveau le serveur avec son client_id, son client_secret, le code qu’il vient de recevoir ainsi que l’url de redirection pour la création de session côté client.
  4. Le serveur vérifie alors les identifiants de connexion du client, et créé le token pour l’utilisateur demandé. Le token est alors renvoyé à l’url de redirection demandée.

La session peut maintenant être créée côté serveur. Le client aura désormais accès aux méthodes exposées par l’API du serveur pour accéder aux données de l’utilisateur.

Configuration de l’OAuth Server

Après l’installation du bundle , 4 entités doivent être définies et étendre les entités du bundle : Client, AccesToken, RefreshToken et AuthCode. Pour l’utilisateur, nous utilisons notre propre entité User qui étend les propriétés du User de FOS. Nous pourrons ainsi donner de nouvelles propriétés aux utilisateurs qui pourront être synchronisées via RabbitMQ avec tous les clients.

Chaque Client dispose d’un client_id et d’un client_secret qui lui permettront de s’identifier auprès du serveur Quovadis Connect.

À chaque connexion d’un utilisateur, un AccessToken sera généré pour le User et le Client demandés avec une date d’expiration. Un RefreshToken sera aussi créé pour permettre de générer un nouveau token.

La configuration des firewalls du serveur est la suivante :

Configuration d’un OAuth Client

La configuration de HWIBundle côté client :

Nous avons créé notre propre provider quovadis.provider.user pour les utilisateurs afin de répondre à deux problèmes :

  • créer les utilisateurs à la volée lorsqu’ils ne sont pas encore enregistrés sur ce client : malgré la synchronisation des données via RabbitMQ, il faut anticiper une éventuelle panne du système et pouvoir créer l’utilisateur s’il n’existe pas encore
  • ne pas créer de doublon pour les utilisateurs se connectant avec différents modes de connexion (Quovadis, Facebook, Twiter, etc.) et utilisant la même adresse mail

Vous trouverez ici un exemple de provider dont nous nous sommes inspiré : https://gist.github.com/danvbe/4476697#file-fosubuserprovider-php

La configuration des firewalls du client est la suivante :

Synchronisation des données via RabbitMQ

Ce bloc fonctionnel est appelé Quovadis Sync. C’est un web service fonctionnant avec RabbitMQ et permettant la synchronisation des données utilisateurs sur tous les sites de Quovadis en se basant sur leur OpenID Quovadis.

Tous les sites utilisant l’OpenID Quovadis peuvent gérer leurs propres informations sur les utilisateurs. Cependant, ces informations doivent être synchronisées avec l’interface de connexion centralisée Quovadis Connect et peuvent aussi être modifiées sur ce site.

RabbitMQ

RabbitMQ est un logiciel open source de Message Queuing basé sur le protocole AMQP (Advanced Message Queuing Protocol). Nous l’avons installé à l’aide de Docker qui propose un repository rabbitmq. L’installation se fait en quelques secondes et propose le très pratique plugin de management de RabbitMQ dont voici une capture d’écran :

RabbitMQ Management Plugin

Architecture

RabbitMQ Architecture

Exchange, queues et routing_key

Pour structurer les échanges de message via RabbitMQ, nous avons mis en place un exchange, une queue par service et plusieurs routing_key relatives aux actions réalisées sur les utilisateurs.

Un exchange central quovadis_sync_exchange permet de recueillir et dispatcher tous les messages. De type topic, cet exchange fonctionne sur la base de routing_keys composées de mots séparés par des points. À chaque message est associé une routing_key qui va permettre d’envoyer ou non le message sur toutes les queues qui sont rattachées à notre exchange. Par exemple, toutes les queues de cet exchange ayant pour routing_key user.update vont recevoir les messages ayant cette routing_key. Mais on peut aussi définir une routing_key user.* qui recevra tous les messages avec une routing_key composée de deux mots dont le premier est user : user.* permettra donc de recevoir à la fois les messages user.create, user.update et user.delete.

Chaque site Quovadis aura sa propre queue sur laquelle sont stockés temporairement les messages qu’elle doit consommer. Nous avons défini des queues comme durable et sans auto_delete. Avec ces paramètres, lorsqu’un site devant consommer des messages d’une queue plante pendant une transaction avec RabbitMQ, ce dernier n’ayant pas reçu l’acknowledgement du site remettra le message dans la queue jusqu’à ce que le site rétablisse la connexion avec RabbitMQ. Ainsi, aucun message n’est perdu.

RabbitMQBundle

Pour toutes nos applications Symfony2 communiquant avec RabbitMQ, nous avons utilisé RabbitMQBundle. Ce bundle est très complet et a répondu à tous nos besoins pour l’utilisation de RabbitMQ.

Voici un exemple de configuration pour le site Quovadis Connect :

Ainsi, pour notifier RabbitMQ de la création d’un nouvel utilisateur, il nous a simplement fallu attacher un Subscriber à l’évènement FOSUserEvents::REGISTRATION_CONFIRMED de FOSUser et appeler la méthode registrationConfirmed() présentée ici :

Enfin, pour lancer le consumer déclaré dans notre configuration, la simple commande suivante permet d’écouter notre queue quovadis_connect_user_queue et d’en récupérer les nouveaux messages :

app/console rabbitmq:consumer user

Team

L’équipe pour ce projet AppVentus :

comments powered by Disqus