Drupal 10 : Simplification de l’Authentification OAuth 2.0 avec un Middleware Personnalisé

Introduction

Lors de l’authentification via OAuth 2.0, la nécessité de fournir plusieurs paramètres, tels que client_id, client_secret, et grant_type, en plus des informations d’identification de l’utilisateur, peut rendre le processus complexe et propice aux erreurs. Cet article explore comment simplifier cette procédure en utilisant un middleware personnalisé. Ce middleware permet de réduire la charge de saisie pour l’utilisateur en automatisant la gestion des paramètres requis pour l’authentification.

Prérequis

Avant de procéder à la configuration, veuillez vous assurer de satisfaire aux conditions suivantes :

Use Case

Nous allons simplifier l’authentification OAuth 2.0 en réduisant le nombre de paramètres nécessaires pour obtenir un token via l’API /oauth/token. Actuellement, il est nécessaire de fournir plusieurs paramètres, ce qui peut être fastidieux. Pour améliorer l’expérience utilisateur, nous créerons un middleware dans le module personnalisé custom_auth qui définira des paramètres par défaut de sorte que la requête soit complétée si le client ne fournit pas l’ensemble des informations. Ainsi, l’utilisateur n’aura qu’à entrer son nom d’utilisateur et son mot de passe, tandis que le middleware s’occupera automatiquement d’ajouter les autres paramètres nécessaires à l’authentification.

Le middleware gère également les requêtes de refresh token, où le type de requête (grant_type) est automatiquement défini comme refresh_token si un refresh_token est présent dans la requête. Cela simplifie encore davantage la gestion des tokens en offrant une expérience utilisateur cohérente et sécurisée.

De plus, cette solution permettra aux clients (applications web, mobiles, etc.), selon leurs besoins, de renseigner le client_id et le grant_type, qui sont des informations publiques et ne posent pas de problème de sécurité. En revanche, le client_secret ne doit pas être fourni par des applications web ou mobiles, car il pourrait être exposé aux utilisateurs, compromettant sa confidentialité. Cette approche non seulement simplifie le processus d’authentification, mais renforce également la sécurité en limitant l’exposition des informations sensibles.

Paramètres dans settings.php

Les paramètres nécessaires à l’authentification, comme client_id, client_secret, et grant_type, sont configurés directement dans le fichier web/sites/default/settings.php de Drupal. Cela permet une gestion centralisée des informations sensibles et des configurations globales, facilitant ainsi l’intégration et la maintenance. Dans la version 6 bêta de Simple OAuth, il n’est plus nécessaire de créer plusieurs consumers en fonction des rôles des utilisateurs. En effet, chaque utilisateur connecté maintient ses droits existants, ce qui simplifie la gestion des consumers et évite la complexité liée à la récupération du consumer approprié selon le rôle, comme c’était le cas dans la version 5 de Simple OAuth. Voici un exemple de configuration :

$config['system.site']['oauth_client_id'] = 'QOf6alZN9a9ZB2bLG0o9qVPeNKCAeMB6UANmcSdXie4';
$config['system.site']['oauth_client_secret'] = 'oauth';
$config['system.site']['oauth_grant_type'] = 'password';

Création du middleware

Nous avons d’abord créé un dossier Middleware dans le répertoire custom_auth/src pour y placer notre middleware personnalisé. Ce dossier contient le fichier OauthMiddleware.php, qui implémente le middleware suivant :

<?php
namespace Drupal\custom_auth\Middleware;

use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\HttpKernelInterface;
use Drupal\Core\Session\AccountInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal;

class OauthMiddleware implements HttpKernelInterface {

  protected $httpKernel;
  protected $currentUser;
  protected $entityTypeManager;

  public function __construct(HttpKernelInterface $httpKernel, AccountInterface $currentUser, EntityTypeManagerInterface $entityTypeManager) {
    $this->httpKernel = $httpKernel;
    $this->currentUser = $currentUser;
    $this->entityTypeManager = $entityTypeManager;
  }

  public function handle(Request $request, int $type = self::MAIN_REQUEST, bool $catch = true): Response {
    if (!$this->isOauthTokenRequest($request)) {
      return $this->httpKernel->handle($request, $type, $catch);
    }

    $this->setOauthParameters($request);

    return $this->httpKernel->handle($request, $type, $catch);
  }

  /**
   * Check if the request is for obtaining an OAuth token.
   */
  private function isOauthTokenRequest(Request $request): bool {
    return $request->getPathInfo() === '/oauth/token';
  }

  /**
   * Set OAuth parameters on the request.
   */
  private function setOauthParameters(Request $request): void {
    $clientId = $this->getOauthClientId();
    $clientSecret = $this->getOauthClientSecret();

    if ($this->isRefreshTokenRequest($request)) {
      $this->setRequestParams($request, $clientId, $clientSecret, 'refresh_token');
    } else {
      $grantType = $this->getOauthGrantType();
      $this->setRequestParams($request, $clientId, $clientSecret, $grantType);
    }
  }

  /**
   * Check if the request contains a refresh_token.
   */
  private function isRefreshTokenRequest(Request $request): bool {
    return $request->request->get('refresh_token') !== null;
  }

  /**
   * Set parameters on the request if necessary.
   */
  private function setRequestParams(Request $request, string $clientId, string $clientSecret, string $grantType): void {
    $this->setRequestParamIfMissing($request, 'client_id', $clientId);
    $this->setRequestParamIfMissing($request, 'client_secret', $clientSecret);
    $this->setRequestParamIfMissing($request, 'grant_type', $grantType);
  }

  /**
   * Set a parameter on the request if it's not already present.
   */
  private function setRequestParamIfMissing(Request $request, string $param, string $value): void {
    if (!$request->request->get($param)) {
      $request->request->set($param, $value);
    }
  }

  /**
   * Retrieve the OAuth client ID from configuration.
   */
  private function getOauthClientId(): string {
    return \Drupal::config('system.site')->get('oauth_client_id');
  }

  /**
   * Retrieve the OAuth client secret from configuration.
   */
  private function getOauthClientSecret(): string {
    return \Drupal::config('system.site')->get('oauth_client_secret');
  }

  /**
   * Retrieve the OAuth grant type from configuration.
   */
  private function getOauthGrantType(): string {
    return \Drupal::config('system.site')->get('oauth_grant_type');
  }
}

Ce middleware intercepte les requêtes adressées à l’API /oauth/token et automatise l’ajout des paramètres nécessaires à l’authentification. La méthode handle() vérifie d’abord, via isOauthTokenRequest(), si la requête concerne l’obtention d’un token OAuth. Si tel est le cas, setOauthParameters() récupère et complète les paramètres essentiels comme client_id, client_secret et grant_type. Ces informations sont automatiquement extraites des configurations du site via les méthodes getOauthClientId(), getOauthClientSecret() et getOauthGrantType(), qui utilisent \Drupal::config() pour accéder aux valeurs définies dans le fichier settings.php. Lorsqu’une requête de rafraîchissement de token est détectée par isRefreshTokenRequest(), le paramètre grant_type est défini sur refresh_token. Les paramètres manquants sont ensuite ajoutés à la requête via setRequestParams() et setRequestParamIfMissing(). Une fois complétée, la requête est transmise au gestionnaire principal pour traitement. Cette approche rationalise le processus d’authentification en automatisant la gestion des informations sensibles tout en garantissant sécurité et simplicité.

Configuration du service

Une fois le middleware créé, il doit être enregistré en tant que service pour être utilisé dans l’application Drupal. Ce service est configuré dans le fichier custom_auth.services.yml pour être injecté dans le pipeline de requêtes HTTP. Voici l’extrait de configuration :

services:
  custom_auth.oauth_middleware:
    class: Drupal\custom_auth\Middleware\OauthMiddleware
    arguments: ['@current_user', '@entity_type.manager']
    tags:
      - { name: http_middleware, priority: 100, after: 'basic_auth' }

Ce fichier enregistre le service custom_auth.oauth_middleware, utilisant la classe OauthMiddleware. Ce service est configuré avec deux arguments : @current_user, représentant le service utilisateur actuel de Drupal, et @entity_type.manager, le service responsable de la gestion des entités comme les utilisateurs et les contenus. Il est également balisé avec le tag http_middleware pour intercepter les requêtes HTTP. Sa priorité est définie sur 100, assurant son exécution après le middleware basic_auth pour ajouter les paramètres OAuth nécessaires.

Test

Pour tester cette configuration, effectuez une requête POST à l’URL /oauth/token en fournissant uniquement le nom d’utilisateur (username) et le mot de passe (password) dans le corps de la requête. Le middleware se chargera automatiquement d’ajouter les paramètres manquants, tels que client_id, client_secret, et grant_type, en utilisant les valeurs définies dans les configurations. Si tout est correctement configuré, l’API OAuth renverra un token d’authentification.

Le test a été réalisé en utilisant Apidog, un outil efficace pour gérer et tester les API.

Conclusion

L’implémentation d’un middleware personnalisé dans Drupal 10 pour la gestion de l’authentification OAuth 2.0 simplifie considérablement le processus de connexion pour les utilisateurs. En réduisant le nombre de paramètres nécessaires dans les requêtes, ce middleware permet aux utilisateurs de se concentrer uniquement sur la saisie de leur nom d’utilisateur et de leur mot de passe, tandis que les autres paramètres essentiels sont automatiquement fournis. Cette solution améliore l’expérience utilisateur en offrant un processus de connexion plus fluide et plus sécurisé, tout en facilitant le développement frontend en évitant la gestion manuelle des paramètres OAuth.

Développeuse fullstack * Plus de publications

Développeuse fullstack spécialisée en Systèmes d'Information Répartis , diplômée de la section informatique de la Faculté des Sciences et Techniques (FST) de l'UCAD. Je relève avec passion des défis complexes, avec une forte capacité d'adaptation et un engagement pour la collaboration en équipe. Toujours avide d'apprendre, je vise à créer un impact positif et à promouvoir l'excellence organisationnelle dans chaque projet.

Contributeurs

0 0 votes
Évaluation de l'article
guest
0 Commentaires
Le plus ancien
Le plus récent Le plus populaire
Commentaires en ligne
Afficher tous les commentaires

Ingénierie informatique (SSII)

Applize crée des logiciels métiers pour accompagner les entreprises dans la transition vers le zéro papier.


Avez-vous un projet en tête ? Discutons-en.