De nos jours, les Systèmes d’Information doivent être flexibles afin de répondre aux enjeux de l’économie digitale. Cette ouverture n’est cependant pas sans conséquences et la sécurisation du droit d’accès aux ressources exposées devient, plus que jamais, critique pour l’ensemble des entreprises.
Sans les mécanismes d’authentification, pour donner accès à une application tierce, il faut y stocker “en clair” les identifiants de l’utilisateur. Cette pratique entraîne de nombreux risques en cas de compromission. De plus, il est impossible de limiter les droits de l’application de façon standardisée et d’identifier l’entité souhaitant accéder aux ressources s’avère compliqué. Ce qui ouvre la porte aux abus et laisse l’utilisateur et le Système d’Information sans défense.
Parmi les nombreux protocoles de sécurisation des API existants, on peut citer OAuth2, OIDC, SAML, Kerberos parmi les plus couramment utilisés. Arrêtons-nous sur les très populaires OAuth2 et OIDC.
Qu’est-ce qu’OAuth2 ?
OAuth2 est un protocole d’autorisation standard. Il se concentre sur la simplicité de l’authentification côté clients, tout en fournissant des flux d’autorisation spécifiques pour les applications web, les applications de bureau, les téléphones et les appareils de salon.
Il fonctionne sur le principe de la délégation d’accès. Son but principal est donc de décrire comment l’accès aux API sécurisées d’une application ou d’un site web (fournisseur) va être délégué à une autre application (consommateur).
Les rôles dans Oauth2 :
OAuth2 définit quatre rôles pour les utilisateurs et les applications :
- Propriétaire de la ressource
- Client
- Serveur de ressources
- Serveur d’autorisation
Propriétaire de la ressource : l’utilisateur
Le propriétaire de la ressource est l’utilisateur qui autorise une application à accéder à son compte. L’accès de l’application au compte de l’utilisateur est limité à la « portée » de l’autorisation accordée (par exemple accès en lecture ou en écriture).
Serveur de ressources/d’autorisation : API
Le serveur de ressources héberge les comptes d’utilisateurs protégés, et le serveur d’autorisation vérifie l’identité de l’utilisateur puis délivre des jetons d’accès à l’application.
Du point de vue d’un développeur d’applications, l’API d’un service remplit à la fois les rôles de serveur de ressources et d’autorisation. Nous appellerons ces deux rôles combinés, le rôle de service ou d’API.
Client : candidature
Le client est l’ application qui souhaite accéder au compte de l’utilisateur. Avant de pouvoir le faire, il doit être autorisé par l’utilisateur, et l’autorisation doit être validée par l’API.
L’utilisation de OAuth2 :
Le schéma ci-dessous nous explique les étapes à valider pour avoir un accès à un service protégé via un serveur de ressources.
Authentification :
* L’application cliente demande au serveur d’autorisation un jeton (= Access Token) en échange de son identifiant (client_id) et éventuellement son client secret (client_secret). C’est aussi à cette étape que l’utilisateur peut être authentifié.
*Le serveur d’autorisation vérifie les données de l’application (et de l’utilisateur s’il y en a un).
*Il délivre à l’application cliente un Access Token qui servira de preuve d’authentification.
Consommation de la ressource (une fois que l’application cliente a obtenu son Access Token) :
*Dans une autre requête, l’application transmet l’Access Token au serveur de ressources.
*Le serveur de ressources vérifie que l’Access Token est valide et que ses privilèges sont suffisants pour accéder à la ressource.
*Le serveur de ressources envoie les données de la ressource à l’application cliente.
Pour éviter de demander régulièrement à l’utilisateur de saisir son login et mot de passe, OAuth2 prévoit le renouvellement de l’Access Token à l’aide d’un Refresh Token. OAuth2 prévoit aussi la révocation du Token (à utiliser par exemple à la déconnexion de l’utilisateur).
4 scénarios pour obtenir un token.
OAuth2 propose 4 scénarios, ou “flows” :
Client Credentials Grant
Commençons par le scénario le plus “simple”. Contrairement aux autres, il ne permet pas à un client d’effectuer des actions au nom d’un utilisateur : il ne fait que fournir un token à un Client pour l’identifier auprès d’un serveur de ressources.
Ce scénario est très utile pour des cas où vous avez besoin d’un “utilisateur technique” pour des traitements serveur à serveur (batch ou d’autres actions d’administration). Il permet aussi à des applications de mettre à jour leurs propres informations (nom de l’application, pays, conditions d’utilisation…)
Puisque le client va devoir être authentifié, il devra savoir conserver ses identifiants en sécurité : ce scénario ne doit donc être utilisé que pour des clients confidentiels ou externes.
Resource Owner Credentials Grant
Dans ce scénario, le client reçoit un token directement depuis le serveur d’autorisation sur un endpoint /token. Pour identifier le Resource Owner, le client a la responsabilité de récupérer les identifiants de l’utilisateur. Ces informations étant des données sensibles, ce scénario est seulement acceptable dans le cas d’un client confidentiel.
Il est particulièrement utile pour des applications legacy qui fonctionnaient auparavant en récupérant directement les identifiants de l’utilisateur. Il peut servir de substitution (pas de changement du point de vue de l’expérience utilisateur), l’avantage principal étant que l’application legacy n’a plus besoin de stocker les identifiants utilisateur car elle va se contenter du token d’accès.
Implicit Grant
Ce flow est conçu pour des clients publics. Dans le scénario “implicite”, il n’y a pas de code d’autorisation intermédiaire envoyé au client. Le token d’accès lui est envoyé directement via une URL de confiance connue par le Serveur d’Autorisation (redirect url).
Cette URL ne doit n’être accessible qu’avec le protocole HTTPS et inclure un programme Javascript capable de lire le token à partir du fragment de l’URL correspondante. À partir de là, le token peut être utilisé par cette application Javascript.
Authorization Code Grant
Le scénario “Authorization Code Grant” est le scénario “traditionnel”, hérité d’OAuth1 et simplifié. Il est conçu pour gérer la communication de serveur à serveur, pour un service web (c’est-à-dire dans le cas où l’utilisateur final utilise un navigateur web).
Il y a donc trois serveurs en présence, le Serveur d’Autorisation, le Serveur de Ressources et le Client : on appelle donc souvent ce scénario un three-legged flow.
OpenID Connect
OpenID Connect(OIDC) spécifie une interface HTTP Restful d’authentification et se base sur le protocole Oauth2 pour faire de la délégation d’autorisation , c’est à dire OIDC utilise le formalisme d’échange JWT ( JSON WEB TOKEN) pour transmettre l’identité des utilisateurs aux applications , ainsi que leur rôles et leur droits d’accès.
c’est une surcouche à OAuth2 , il ajoute des fonctionnalités qui manquaient à OAuth2 et qui permet de répondre à tous les cas d’utilisation .
Parmi les fonctionnalités ajoutés par OpenID :
- Standardisations des informations utilisateurs.
- La gestion de la session SSO ( single sign on et singe logout par exemple).
- La notion du TOKEN ID
- Une nouvelle API pour récupérer les informations utilisateurs
Principe
Dans un scénario Authorization Code Grant ou Implicit Grant, le client demande au Serveur d’Autorisation un token avec un certain nombre de scopes métier, auquel viendra s’ajouter le scope spécifique “openid”.
Lorsque le Serveur d’Autorisation génère le token d’accès OAuth (qu’on appellera par la suite access_token), il fournit aussi un token d’identité (qu’on appellera id_token). Cet ID Token contient des détails sur l’identité de l’utilisateur et le processus utilisé pour l’authentifier. L’ID Token prend la forme d’un JWT signé (plus de détails sur ce format de token plus bas). La spécification OpenID Connect définit aussi un nouvel endpoint /userinfo qui retourne l’identité de l’utilisateur (cet endpoint est à destination du serveur de ressources).
La notion du Token ID :
un token ID est un jeton qui contient l’identité d’un user, il est constitué principalement :
1 – Paramètres de l’authentification : (date d’expiration , date de création , date d’authentification,des infos pour contrôler ID token et accès token)
2- Rôles de l’utilisateur.
3-attributs standards ( profile , email , adresse, phone).
4-attributs privées : on le précise pour éviter les collision avec les claims qui existent.
Exemple d’un ID TOKEN :
{
« iss »: « http://exemple »,
« sub »: « 24400320 »,
« aud »: « s6BhdRkqt3 »,
« nonce »: « n-0S6_WzA2Mj »,
« exp »: 1515604697,
« iat »: 1515593897,
« name »: « kharrat Abderrahmen »,
« given_name »: « abder »,
« family_name »: « kharrat »,
« gender »: « male »,
« email »: « abderrahmen.kharrat@devoteam.com »,
« acr »: [« role1″, »role2 », « role3 »]
}
⇒ OpenID fournie plusieurs interfaces qui sont :
autorisation , token , user info , révocation , introspection.
Authorization Flow.
OpenID Connect propose trois algorithmes pour déterminer comment retourner et générer des tokens qui sont :
1) Autorisation code Flow.
2) Implicite Flow.
3) Hybrid Flow.
Tenons l’exemple de Autorisation code flow :
la spécification prévoit également que l’openID Provider demande le consentement de l’utilisateur sur l’accès aux données de son identité
(accès à des périmètres précis , mail , adresse , téléphone).
Notons que la récupération des informations utilisateurs « userInfo request » n’est pas obligatoire puisque l’ID Token peut être alimenté avec les informations lors de la demande de token.
Le flow OAuth2 Authorization Code décrit plus haut s’applique, avec quelques spécificités. Vous devez d’abord rediriger le navigateur web (ou l’appareil mobile) vers l’URL d’autorisation, avec le paramètre scope pré-rempli, et ce scope doit contenir “openid”. D’autre part vous devez remplir le paramètre “response_type” avec la valeur “code”.
GET /authorize?
response_type=code
&scope=openid%20profile%20email%20my_other_scopes
&client_id=…
À la fin des opérations utilisateur (connexion avec login/mot de passe, puis étape de consentement), le navigateur sera redirigé vers le serveur du client, avec le code d’autorisation inclus dans les paramètres de la requête. Le serveur devra alors échanger le code d’autorisation contre un access token et un ID Token. La requête prendra cette forme :
POST /token
Authorization: Basic fUDU0kwep5p9NgythBmufFDM
grant_type=authorization_code
&code=RCxPxxcFYlunAuD9zSrQNS4C
&redirect_uri=…
Pour obtenir la réponse :
HTTP/1.1 200 OK
Content-Type: application/json
{
« access_token »: « EpjZGJrprScYUD9SPSKHjSM1HOYBGKhB »,
« token_type »: « Bearer »,
« refresh_token »: « 7AJ1C1hc6xR4aUicZjU6HeW6tKlXsNIn »,
« expires_in »: 3600,
« id_token »: « eyJhbGciOiJSUzI1NiIsImtpZCI6IjFlOWdkazcifQ.ewogImlzcyI6ICJodHRwOi8vc2VydmVyLmV4YW1wbGUuY29tIiwKICJzdWIiOiAiMjQ4Mjg5NzYxMDAxIiwKICJhCyixEoV9GfNQC3_osjzw2PAithfubEEBLuVVk4XUVrWOLrLl0nx7RkKU8NXNHq-rvKMzqg »
}
L’ID Token a l’air peu engageant ! Mais toutes les informations décrites dans la section précédente y sont bien présentes, sous la forme un peu particulière d’un Json Web Token (voir ci-dessous).
→ Comme expliqué dans les parties précédentes , OAuth2.0 et OIDC se base sur le transfert d’un Json Web Token.
Dans la partie suivante , on va s’intéresser à la composition du JWT.
Focus sur JWT
JWT est un jeton permettant d’échanger des informations de manière sécurisée. Il est souvent utilisé pour offrir une authentification stateless au sein d’applications.
Un token json web token est constitué principalement de 3 parties séparées par un point virgule.
Header :
Le header décrit l’algorithme utilisé pour chiffrer ou signer un token.
Exemple :
{« alg »: »HS256″, »typ »: »JWT »}
Payload :
c’est le contenu d’un token et doit être encodé en base64 par la suite,
{
« jti »: « f232b54cb285452db02770c9d16f8f212151 »,
« iss »: « http://exemple.fr »,
« sub »: « 24400320 »,
« aud »: « s6BhdRkqt3 »,
« nonce »: « n-0S6_WzA2Mj »,
« exp »: 1515604697,
« iat »: 1515593897,
« name »: « kharrat abderrahmen »,
« given_name »: « abder »,
« family_name »: « kharrat »,
« gender »: « male »,
« email »: « abderrahmen.kharrat@devoteam.com »,
« acr »: [« role1″, »role2 », « role3 »]
}
Signature du token :
elle est effectuée en utilisant algorithme de signature a partir :
*du header au format base64 url encodé,
*du payload au format base64 encodé,
*de la clé privée du serveur d’autorisation,
Exemple :
HMACSHA256(
Base64UrlEncode(header) + « . » +
Base64UrlEncode(payload),
clé privé
)
⇒ au final , nous obtenons un jetons JWS ( s : signifie signée) encodé en base64 :
Conclusion :
OpenID Connect et OAuth 2 apportent une réelle valeur ajoutée aux organisations souhaitant disposer d’une fédération d’identités centralisée. Ils sont devenus les standards incontournables lorsqu’il s’agit d’adresser des problématiques SSO entre services et applications de leur SI. En effet les informations étant normalisées, tout comme leur formalisme d’échange (via JWT), l’interopérabilité entre les applications est garantie, et l’intégration n’en est que plus facile et rapide.
Voilà qui conclut cet article. Vous devriez maintenant avoir une bonne idée du fonctionnement d’OAuth 2 et du moment où un flux d’autorisation particulier doit être utilisé.
Bonne sécurisation !