OAuth 1.0 en bref

Cette article fait partie d’une série dédiée au protocole OAuth

1 – OAuth 1.0 en bref
2 – Exemple de Twitter avec C# et HttpClient

Aujourd’hui utilisé par bon nombre de services populaires, comme Twitter, Tumblr ou encore Facebook, pour exposer leur API publique, OAuth est un protocole d’autorisation qui en est aujourd’hui à sa version 2.0. Il réside certaines différences assez notables entre la version 1.0 et la plus récente, la 2.0. Néanmoins, ce protocole est encore utilisé dans sa version 1.0 par des services très populaires, comme Twitter, c’est donc pour cela que cet article traitera de la version 1.0.

Cet article se veut volontairement détaché de tout langage de programmation pour cibler n’importe quel développeur curieux. Néanmoins il sera suivi d’un article d’exemple d’implémentation de l’OAuth 1.0 en C# pour effectuer une requête à l’API Twitter

Pourquoi OAuth ?

Avant d’expliquer pourquoi OAuth, mettons d’abord en évidence les différents acteurs impliqués dans ce protocole:

  • Le propriétaire des ressources, autrement dit : l’utilisateur final. Il souhaite accéder à un service sur un serveur hébergeant des données qui lui sont propres.
  • Le serveur : le service en lui même hébergeant les ressources de l’utilisateur et mettant en place une API utilisable par des applications tierces.
  • Le client : application ou site web tiers non affilié au serveur fournissant le service. Ce client doit être explicitement autorisé par le propriétaire des ressources d’accéder aux ressources appartenant au client sur le serveur.

Pour donner un exemple de ces trois entités, imaginez un utilisateur final ayant installé une application sur son Smartphone permettant de faire des achats en ligne. Une fois ses achats effectués, l’utilisateur est invité par l’application à mettre à jour son statut Facebook pour montrer à ses amis qu’il a utilisé cette application pour acheter certaines choses. Ainsi, l’application “facilite” le travail de l’utilisateur en pré-remplissant le texte du statut et en y ajoutant une photo correspondante, il suffit alors à l’utilisateur de valider directement depuis l’application pour voir son statut Facebook mis à jour. Dans cet exemple, le propriétaire de ressources est l’utilisateur de l’application, l’application est le client et Facebook est le serveur. Ainsi l’utilisateur possède des informations personnelles (propriétaire de ressources) sur Facebook (serveur) et délègue la rédaction de son statut à l’application smartphone (le client).

OAuth a vu le jour face au potentiel risque de sécurité qui pouvait se poser lorsque le propriétaire de ressources ne pouvait s’authentifier à une API d’un serveur par le biais d’un client tiers que par son couple identifiant/mot de passe. Ainsi pour maintenir l’authentification, le client doit garder une trace du mot de passe de l’utilisateur en clair ! De même l’utilisateur ne peut ni donner un accès partiel à un client (par exemple de la lecture seule) ni révoquer l’accès à un client (à moins de modifier son mot de passe, mais cela révoquerai TOUT les accès des clients tiers).

Comme alternative à ça, OAuth propose l’utilisation d’un jeton (access token) propre à l’utilisateur et au client pouvant être valide uniquement dans un certain laps de temps et pour seulement une partie définie des services du serveur. Ainsi, l’utilisateur n’expose à aucun moment son mot de passe au client, il peut donner un accès restreint à ses ressources et peut révoquer ses accès comme bon lui semble sans avoir à changer son mot de passe et sans modifier les accès d’autres clients tiers au service.

OAuth en bref

Processus

Le processus simplifié d’obtention du jeton d’accès est le suivant : le serveur fournit au client sa propre clé unique d’authentification (consumer key) avec sa clé privée (consumer secret). Cette clé du client sera inclue dans une url de redirection envoyée au propriétaire de ressource dirigée vers la page d’authentification du serveur. Ainsi l’utilisateur s’identifie directement au serveur sans fournir son identifiant et son mot de passe au client, et le serveur (grâce à la consumer key contenue dans la requête) pourra identifier le client pour afficher clairement à l’utilisateur quels droits et à qui il est sur le point d’octroyer. Une fois l’authentification sur le serveur faite, un jeton d’accès (access token) sera généré et renvoyé au client (identifié par sa clé ).

Pour faire une comparaison simple de ce que représente un access token, imaginez un parc d’attraction, un trousseau de clé ouvre ce parc et toutes ses attractions, mais pour donner au public l’accès au parc, le gérant ne va pas, en toute logique, faire des copies du trousseau de clés pour les donner aux visiteurs car de cette manière il leur donne accès à TOUT le parc, même les zones interdites et cet accès sera impossible à révoquer, sauf en changeant les serrures, mais changer les serrures interdira alors l’accès à tous les visiteurs ayant eu les clés et pas juste à celui à qui l’on veut interdire l’accès. Au lieu de donner un trousseau, on va simplement donner à chacun un ticket nominatif et chaque ticket aura un type (par exemple “enfant” pour juste les attractions enfantines, un ticket “premium” donnant accès aux spectacles du soir, etc…) et vérifier ce ticket à l’entrée de chaque attraction, ainsi seules les attractions autorisées par le type du ticket seront accessibles et si un visiteur ne respecte pas le règlement intérieur on peut révoquer son ticket sans gêner l’accès des autres visiteurs. De même, le ticket ne sera valable que durant un nombre précis de jours, et non à vie.

Etape par étape:

1 – Le client, identifié par sa clé unique, fait une demande de oauth token au serveur en signant la requête avec sa clé privée.
2 – L’utilisateur est redirigé vers une url sur laquelle il est invité à s’authentifier. Le oauth token doit être fourni soit en paramètre dans l’url soit fourni directement par l’utilisateur.
3 – L’utilisateur s’authentifie et accepte de fournir au client l’accès à ses données via l’API.
4 – Un access token et un access token secret propres à l’utilisateur et au client sont envoyés au client. Plusieurs manières peuvent opérer:
4.a : Si le client est capable de recevoir une requête du serveur, celui ci lui envoi directement la paire de token
4.b : Si le client n’est pas capable de recevoir de requête du serveur (application mobile ou application bureau), un code “PIN” est fourni à l’utilisateur et ce dernier le fourni au client. Le client doit alors refaire une requête au serveur en incluant son oauth token et le PIN de l’utilisateur pour recevoir en réponse le couple d’access token.
5 – A présent le client peut accéder aux données de l’utilisateur en utilisant sa consumer key et l’access token de l’utilisateur tout en signant la requête par le couple consumer secret et access token secret.

(Schéma d’authentification OAuth, cliquez pour voir l’image originale)

Construire et signer les requêtes

Paramètres OAuth

Une requête OAuth consiste en une requête HTTP classique mis à part que celle ci doit être signée par une clé privée. Pour signer la requête, il convient d’abord de distinguer deux types de paramètres qui devront être donnés à la requête: les paramètres OAuth et les autres paramètres liés au service demandé.

Les paramètres oauth sont au nombre de sept:
oauth_nonce : une chaine de caractère aléatoire
oauth_timestamp : nombre de secondes écoulées depuis le 1er janvier 1970
oauth_version : version du protocole, 1.0 dans notre cas
oauth_signature_method : méthode utilisée pour signer la requête, oauth supporte “PLAINTEXT”, “HMAC-SHA1” et “RSA_SHA1”. Néanmoins, les serveurs sont libres de ne pas supporter toutes ces méthodes. Pour la suite nous parlerons de la méthode “ »HMAC-SHA1”
oauth_consumer_key : la consumer key du client
oauth_token : l’access token (uniquement lorsque l’on a effectivement ce token, si on ne l’a pas, on omet ce paramètre)
oauth_signature : la signature de la requête

Le nonce et le timestamp peuvent servir au serveur s’il souhaite limiter le nombre de requêtes avec un même couple timestamp/nonce.

Signer la requête

(NOTE : n’étant pas sur de la traduction française du terme anglophone “percent encode”, j’utiliserais simplement le terme “encoder” pour faire référence à cet encodage. Il consiste à encoder, pour tout les caractères qui ne sont pas alphanumériques ou bien dans l’ensemble “-._~”, par le caractère pourcent ( % ) suivi de la représentation hexadécimale majuscule du caractère, par exemple “:” donne “%3A” )

Signer la requête consiste en la génération d’un signature base string puis de son hachage avec HMAC-SHA1 (hachage SHA1 mais en utilisant une clé de hachage ). La signature base string est composé de (dans l’ordre EXACT au caractère et à l’encodage près ! ) :

  • La méthode HTTP en majuscule (GET, POST, DELETE,….)
  • Un caractère ‘&’
  • L’url de base (sans les paramètres GET) encodée
  • Un caractère ‘&’
  • L’ensemble des paramètres placés de la manière suivante :
    • Les paramètres doivent être placés par ordre alphabétique de leur nom
    • Chaque paramètre est séparé par un ‘&’
    • Le nom et la valeur de chaque paramètre sont placés ainsi : le nom encodé, le caractère ‘=’ et la valeur encodée (s’il n’y a pas de valeur, nous ne plaçons rien entre le ‘=’ et le ‘&’ séparant du paramètre suivant)

Une fois la signature base string obtenue, nous la hachons avec la ou les clés privées concaténées de la manière suivante:
-La clé consumer secret
-Un caractère ‘&’
-Si l’utilisation de l’access token secret s’applique, nous la concaténons, sinon nous nous arrêtons là pour la formation de la clé de hachage.
 

Obtenir l’Authorization Header

L’authorization header sera une information placée dans le header “Authorization” de la requête. Il contiendra les paramètres oauth utilisés précédemment en y ajoutant la signature. C’est à partir de cet authorization header que le serveur récupèrera les informations lui permettant ou non d’autoriser la requête, cet header sera formé de la manière suivante:

  • le mot  “OAuth” suivi d’un espace
  • chaque paramètre oauth placés de la manière suivante
    • Chaque paramètre est séparé par un espace
    • Le nom et la valeur de chaque paramètre sont placés ainsi : le nom, le caractère ‘=’, le caractère ‘ »’ (double quote), la valeur encodée et un autre caractère ‘ »’ (double quote)

Puis il ne manque plus qu’à renseigner le header “Authorization” avec la valeur obtenue précédemment.

Vérifications

Une fois la requête construite et signée, il ne vous manque plus qu’à lui ajouter les autres paramètres (tous ceux qui ne commencent pas par “oauth_”); pour la méthode HTTP GET en mettant les paramètres dans l’url, pour les autres méthodes dans le header “Content”.

Lors du développement, à des fins de tests et de vérifications, je vous conseille d’utiliser la console de test oauth de Linkedin. Si vous lui fournissez les paramètres qu’elle demande, elle vous fournira la signature base string, la signature ainsi que l’authorization header que vous devriez obtenir. Etant donné que cette console de test ne produit aucune vrai requête à l’url que vous lui fournissez, rien ne vous empêche de ne pas lui fournir vos vrais clé mais plutôt des fausses clés que vous utilisez pour tester simplement la construction de la signature et des header.

Pour une documentation beaucoup plus exhaustive, vous pouvez consulter la norme RFC 5849 (en anglais).

Par Mathieu Hollebecq

Laisser un commentaire

Entrez vos coordonnées ci-dessous ou cliquez sur une icône pour vous connecter:

Logo WordPress.com

Vous commentez à l'aide de votre compte WordPress.com. Déconnexion / Changer )

Image Twitter

Vous commentez à l'aide de votre compte Twitter. Déconnexion / Changer )

Photo Facebook

Vous commentez à l'aide de votre compte Facebook. Déconnexion / Changer )

Photo Google+

Vous commentez à l'aide de votre compte Google+. Déconnexion / Changer )

Connexion à %s