Nouvelles Chroniques d'Amethyste

Penser au Sens, pas au Verbe

Sécuriser ses applications avec Azure AD: la synthèse

Poster un commentaire

Au fil du temps j’ai rédigé plusieurs articles concernant les questions liées à l’authentification. Ces articles sont nombreux et dispersés un peu partout.

Je pense donc qu’il est temps de réaliser un article de synthèse qui va donner des liens vers les différents articles concernés et proposer quelques informations supplémentaires de contexte.

Au fur et à mesure que la série s’étoffera, je rajouterai quelques lignes dans cet article.

 

Des informations de synthèse donc, des liens utiles, mais pas de code ici. Au menu:

  • Une vision infra
  • Identification, authentification et autorisation
  • Quels protocoles d’authentification?
  • Les claims
  • Les deux types de compte
  • Je suis devant Visual Studio, je fais quoi?
  • Scénarios OAuth 2
  • Les jetons
  • Adal

 

Une vision infra

Une chose sur laquelle je souhaiterai insister: je suis développeur, l’audience de ce blog sont les développeurs, même si tout le monde est le bienvenu!

Je ne suis donc pas expert en infrastructure. Seulement voilà, un développeur ne peut absolument pas laisser de côté tout ce qui concerne le matos car un jour où l’autre il faudra bien discuter avec les gens de l’infra.

Il y a quelques temps j’ai rédigé un article qui décortique quelques architectures typiques pour mettre en œuvre des solutions de sécurité. C’est une synthèse de tout un tas de lectures à droite à gauche, mais qui m’a donné pas mal de points de repère bien utiles:

https://amethyste16.wordpress.com/2014/11/25/lauthentification-federee-par-claims-les-grands-principes/

Au vu de mon expérience personnelle, je dirait qu’il résume ce qu’un développeur a besoin de connaître sur ce sujet.

Retenez en particulier ceci:

  • le rôle d’ADFS dans les infras on premise
  • Les services proposés par un fournisseur d’authentification (en plus particulièrement Azure AD). J’ai fais un tableau de synthèse.
  • Le point important: ce n’est pas l’application qui fournit l’authentification, mais le fournisseur d’authentification.
    Cela évite de devoir propager ses credentials un peu partout et en particulier vers des applis dont vous ne savez pas au juste ce qu’elles pourraient en faire (les stocker?)
    Simplifie l’administration des comptes et des permissions puisqu’il y a qu’un seul point de terminaison
    On peut de plus mettre en œuvre des stratégies d’authentification par différents tenants (l’utilisateur arrive avec son compte Facebook, Twitter….).
    La mise en œuvre d’une solution de SSO devient naturelle.Et très important: mettre au point et entretenir une infrastructure d’authentification sécurisée est complexe et demande des compétences. Avec Azure, vous pouvez évacuer cette partie de votre solution et vous concentrer sur votre vrai métier.

 

Identification, authentification et autorisation

Le processus de connexion à une application ou un système s’effectue séquentiellement de la façon qui suit:

 

L’architecture de sécurité .Net s’appuie sur l’instanciation d’un principal sous la forme d’un IPrincipal. Le principal désigne l’abstraction par laquelle le système va connaître et interagir avec la personne ou le service, serveur… qui se connecte. La principale propriété d’un principal est son IIdentity qui définie l’identité du principal.

L’identité représente tout ce que l’on peut savoir au sujet de qui s’est connecté. Une caractéristique de l’identité est d’être publique et à ce stade n’engage que moi. Par exemple, ce n’est pas un secret de savoir qu’en fait je suis Brad Pitt….

Une autre caractéristique de l’identité est d’être unique, du moins à l’échelle du système vers lequel on se connecte.

L’identification est l’acte d’établir l’identité de celui qui se connecte. C’est le côté « toc, toc, qui est là? ». Il est en général matérialisé par un formulaire de saisie de credentials.

 

Hélas, il suffit pas de dire « je suis Brad Pitt ». L’authentification consiste à apporter la preuve de mon identité. On est donc plutôt dans la phase: « Ok, tu es Brad, mais peux tu le prouver? ».

Cette preuve est apporté en fournissant un secret, souvent un mot de passe, mais n’importe quel autre secret fait l’affaire. Et oui, cette fois on échange des informations qui ne sont pas publiques.

Le système n’a pas forcément besoin de posséder une copie de ce secret, il lui suffit de pouvoir valider qu’il est authentique. Une caractéristique du secret est qu’il n’est pas forcément unique.

 

Attention, être authentifié ne vous donne pas de droits particuliers sur l’appli, c’est l’étape suivante.

Une fois authentifié (avec succès) à une appli ou un système, celui-ci va donc vous octroyer des autorisations. Dans cette phase, sera vérifié à quelles ressources vous avez accès et en général un jeton vous sera retourné que vous devrez présenter à chaque requête.

 

Note 1: je ne fais pas vraiment de différences entre permissions et droits. Je ne sais même pas s’il y a une nuance!

Note 2: faites attention, en anglais il y a un H  -> authorization

 

Peut être vous demandez vous pourquoi on a besoin d’avoir l’identité ET l’authentification? Pourquoi l’identité doit être unique et surtout pas le secret? On trouvera une excellente explication ici:

https://technet.microsoft.com/en-us/library/cc512578.aspx

Mais quelles que soient vos raisons, je vous invite vraiment à lire cet article.

Quels protocoles d’authentifications?

L’authentification est une longue histoire. Presque aussi ancienne que les réseaux d’ordinateurs. Il n’est pas étonnant qu’au fil du temps de nombreuses stratégies ont été inventées. Je trouve intéressant d’en avoir une vision historique car les plus anciennes cohabitent toujours avec les plus récentes. Par exemple je doute fort que les bon vieux formulaires login/mot de passe  à l’ancienne disparaissent de sitôt.

Lisez donc cet article:

https://amethyste16.wordpress.com/2016/03/07/levolution-des-methodes-dauthentification/

Le point important est que de nos jours OAuth 2 et Open IdConnect doivent faire partie de votre vocabulaire. Vous devez connaître ce qui les différencie.

 

Côté développeur les choses ont également évoluées au fil du temps. Actuellement la couche technique d’authentification proposée par Microsoft s’appelle Identity. J’ai également tracé une perspective historique ici:

https://amethyste16.wordpress.com/2014/08/15/lauthentification-en-asp-net-un-tour-dhorizon/

Les claims

La pierre angulaire des protocoles modernes d’authentification sont les claims. Les claims (ou revendications) sont une liste de propriété/valeurs fournies par le fournisseur d’authentification au sujet de celui qui se connecte sous la forme d’un jeton, mais ils peuvent servir à transférer tout type d’information.

Attention: ce n’est pas un dictionnaire: une clef peut correspondre à plusieurs valeurs.

 

Les claims donnent de la souplesse. Un objet est très dépendant d’un protocole, d’un langage ou de l’infrastructure technique. La structure des claims leur permet de s’adapter à n’importe quel protocole: il est toujours possible de convertir les états d’un objet par une liste de propriétés/valeurs et inversement.

C’est justement ce que fait .NET en proposant une instance de IPrincipal construite à partir des claims:

https://amethyste16.wordpress.com/2014/11/11/gerer-lauthentification-et-les-authorisations-avec-les-claims/

IPrincipal est l’architecture d’authentification standard de .NET depuis son origine. C’est ainsi que les nouveaux protocoles s’insèrent de façon naturelle.

Les deux types de compte

Pour ce qui concerne le sujet de cet article, on dispose de deux types de compte dont le nom évolue au fil du temps. Le nommage actuel est le suivant:

  1. Individual user account
    C’est un compte que vous créez vous même, vous en êtes seul responsable et vous seul pouvez le révoquer.
    C’est par exemple votre compte Hotmail, Google, Twitter…Ce compte peut servir dans un scénario d’authentification auprès d’une organisation détentrice de ressources auxquelles vous souhaitez accéder. Il faut pour cela qu’elle reconnaisse votre fournisseur d’authentification (AS) comme un AS de confiance.Il est important de noter que le fournisseur d’authentification choisit par l’organisation ne procède jamais à l’authentification et en particulier ne fournit jamais elle-même le jeton d’accès. Elle délègue cette tâche à votre fournisseur d’authentification. C’est important car cela garantit que vos credentials ne sont jamais accessibles par l’organisation.L’organisation peut bien entendu révoquer votre compte. Mais n’en étant pas propriétaire, cela ne le supprime pas (heureusement!!!), c’est juste qu’il ne permet plus d’accéder aux ressources protégées.
  2. Work or School account
    Un compte qui vous est fourni par l’organisation dont vous dépendez. Par exemple un compte Azure AD.
    Vous ne le gérez pas, tout au plus il vous est possible de faire quelques configurations comme le choix du mot de passe, de l’avatar…C’est l’organisation qui peut le révoquer. Il est alors perdu. La situation est de ce point de vue très différente du cas précédent.

Je suis devant Visual Studio, je fais quoi?

Vous démarrez un projet, ne vous y connaissez pas trop ou êtes un peu fainéant comme moi. Comment configurer le projet et mettre en place la plomberie OAuth 2?

La bonne nouvelle est que VS propose des assistants qui feront le boulot à votre place. La deuxième bonne nouvelle est que j’ai fais des tutos qui démontrent chacune des options proposées:

https://amethyste16.wordpress.com/2014/07/04/mettre-en-place-lauthentification-avec-visual-studio-2013-partie-i/

https://amethyste16.wordpress.com/2014/08/23/mettre-en-place-lauthentification-avec-visual-studio-2013-partie-ii/

 

Important: les copies d’écran dans les deux tutos qui précèdent sont datées. Le vocabulaire à un peu changé.

Organizational Account a été renommés comme indiqué dans le chapitre précédent ou sur cette copie d’écran.

Il y a d’autres changements dans l’assistant, mais cela ne remet pas en cause le tuto.

Scénarios OAuth 2

OAuth 1 était très simple et ne proposait qu’un seul schéma d’authentification. J’ai rédigé un article qui montre comment utiliser OAuth 1 avec Postman:

https://amethyste16.wordpress.com/2016/12/14/utiliser-oauth-1-avec-postman/

 

OAuth 2 en propose 4:

  1. autorisation via un code (Authorization Code Grant Flow)
  2. Autorisation serveur à serveur (Client Credential Grant Flow)
  3. autorisation via mot de passe (Resource owner password grant flow)
  4. autorisation implicite (Implicit Grant)

 

Le choix de ces scénarios correspond à des situations particulières. Les situations actuellement prises en charge peuvent se résumer ainsi:

  • 1=>4: Navigateur web vers application web
    Un utilisateur doit se connecter à une application Web sécurisée par Azure AD
  • 1=>4: Application SPA  
    Un utilisateur doit se connecter à une application Web sécurisée par Azure AD, mais l’application est une application JavaScript (Ajax)
  • 2=>5: Application native vers API web. 
    Une application native s’exécute par exemple sur un téléphone, une tablette ou un PC. Elle s’authentifie avec un utilisateur pour accéder à des ressources protégées par Azure AD
  • 4=>6: Application web vers web api
    accéder à une ressource sécurisée par Azure AD
  • 3=>5: Démon, service Windows, serveur vers web api
    Des applications sans interface utilisateur web veut obtenir des ressources d’une web api protégées par Azure AD

 

Vous trouverez dans les liens proposés ci-dessous, des exemples de code démontrant chacun de ces scénarios ainsi que leur diagramme de séquence:

 

 

Il reste deux scénarios pour lesquels je n’ai pas publié d’article, mais ils sont pris en charge par Azure AD:

  • 1=>4=>6: Une appli web accède à des ressources protégées par Azure AD, mais aussi à une web api qui elle-même attend des permissions pour accéder à d’autres ressources
  • application multi-tenante: Les utilisateurs peuvent venir non pas du même tenant, mais de plusieurs tenants

 

Quand les employer?

  • autorisation via un code
    C’est celui que l’on doit privilégier si une application de confiance (serveur web en général) se connecte à une ressource sécurisée.
    Le jeton d’accès n’est pas transmit côté client, il est stocké côté serveur et ne sera donc pas accessible à l’extérieur.
  • Autorisation serveur à serveur
    C’est le scénario typique lorsque le client doit accéder à ses propres données. Il n’y a pas besoin qu’il s’accorde des autorisations à lui-même.
  • autorisation via mot de passe
    Dans ce schéma, le client reçoit les identifiants et le mot de passe qui les soumettra lui-même au serveur d’autorisation.
    Cela représente un risque, vous ne savez pas a priori ce que vont devenir vos credentials.Ce scénario n’est donc envisageable que si le client est une application dans laquelle on a confiance, par exemple elle a été développée par votre propre organisation.
  • autorisation implicite
    Le schéma utilisé typiquement lorsque le client est du code JavaScript, par exemple un scénario Ajax ou Angular. C’est à dire des clients qui tournent dans le contexte utilisateur et non pas sur le serveur.Dans ce schéma le client doit gérer les jetons qui seront donc exposés à l’extérieur. C’est pourquoi s’il y a bien un jeton d’accès, le schéma ne prévoit pas de jeton de renouvellement. Celui-ci à une durée de vie très longue (des mois, des années) il n’est pas possible de l’exposer.C’est le schéma le moins bien sécurisé et doit être évité dès que possible.

Pour avoir plus de détails:

http://www.bubblecode.net/fr/2016/01/22/comprendre-oauth2/

 

Vous pouvez également lire ces discussions:

https://stackoverflow.com/questions/13387698/why-is-there-an-authorization-code-flow-in-oauth2-when-implicit-flow-works-s

https://stackoverflow.com/questions/7522831/what-is-the-purpose-of-the-implicit-grant-authorization-type-in-oauth-2

 

J’aime bien aussi ce schéma de synthèse trouvé sur ce site:

https://alexbilbie.com/guide-to-oauth-2-grants/

 

  • First party client: une application de confiance, un client ans lequel on a confiance
  • Third party client: client dans lequel on a pas confiance.
    Pas forcément au sens mafieu du terme, simplement vous société n’a pas écrit son code ou bien elle tourne dans un environnement vulnérable comme l’environnement utilisateur plutôt qu’un de vos serveurs

 

Pour terminer, il n’est pas inutile de souligner que OAuth 2 concerne l’accès à des ressources sécurisées, tandis qu’OpenId Connect concerne l’identification.

Les jetons

Les protocoles modernes s’appuient sur des jetons. Dans le cas d’OAuth 2 seuls les jetons au porteur (bearer token) sont pris en charge. Les jetons au porteur sont définis par la RFC 6750.

 

 

Pour obtenir un jeton au porteur capable de donner accès à une ressource sécurisée il faut passer par un protocole de sécurité. Mais une fois le jeton obtenu, n’importe qui (le porteur) pouvant le présenter accède à la ressource. Il est donc nécessaire de propager les jetons au porteur via un protocole sécurisé.

OAuth 2 n’en propose pas. C’est pourquoi un site sécurisé via OAuth 2 devra toujours être sécurisé par exemple avec TLS (HTTPS)

 

En général on a le choix du format. Un des formats historique est SAML qui est un format XML. JWT est probablement le plus usuel dans le contexte OAuth 2.

Il n’est pas inutile de savoir comment un tel jeton est structuré. Le deuxième article le plus lu sur mon blog explique comment:

https://amethyste16.wordpress.com/2014/08/30/les-jetons-jwt-ce-quun-developpeur-doit-connaitre/

 

Un des avantages de JWT par rapport au simple transfert d’une chaîne genre GUID est que JWT fournit une infrastructure de d’encodage et de signature.

Un jeton est également utile dans d’autres contextes qu’OAuth d’ailleurs, par exemple permettre à deux services d’échanger des informations de façon sécurisée.

 

Azure AD apporte un support à OAuth 2 et OpenId Connect et donc accepte tous les types de jeton liés à ces protocoles:

  1. Refresh_token (jeton de rafraichissement)
    Jeton qui ne peut servir qu’au renouvellement d’un jeton d’accès.
    Par sa nature il a une durée de vie très longue qui peut être de l’ordre du mois ou de l’année
  2. Access token (jeton d’accès)
    C’est le jeton que l’on présente au fournisseur de ressource. On le présente dans le header de sécurité du protocole HTTP sous la forme:Authorization: Bearer <access_token>La durée de vie de ce jeton est très limitée, généralement pas plus d’une heure, mais souvent moins. Une fois expiré, soit on se reconnecte, soit on demande un renouvellement via un refresh_token. Le renouvellement est le plus souvent pris en charge de façon transparente par les infrastructures de sécurité.
    Tous les scénarios OAuth 2 ne supportent pas le jeton de renouvellement.
  3. id_token
    Une forme de jeton de sécurité de connexion propre à OpenId Connect. Il contient donc des informations relatives à l’identité de l’utilisateur

 

Ces jetons sont tous des jetons au porteur.

 

Pourquoi a t’on besoin d’un jeton de rafraichissement?

Le jeton de renouvellement est un jeton à longue durée de vie, on l’a dit. Il sera donc souvent enregistré dans un cache ou une base de données et permettra au service web de réclamer un renouvellement. Dans le cas où le jeton d’accès est compromis, il suffira de supprimer du cache le jeton de renouvellement et attendre que le jeton d’accès se périme pour bloquer à nouveau l’utilisateur pirate.

On voit là toute l’importance de ne pas donner de durée de vie trop longue à un jeton d’accès. Evidemment si ce sont les credentials qui ont été compromis, il pourra toujours se reconnecter…

 

Microsoft propose un petit tuto bien fait sur les jetons:

https://docs.microsoft.com/fr-fr/azure/active-directory/develop/active-directory-token-and-claims

Adal

Du point de vue pratique je conseille de ne pas implémenter à la main la danse du protocole complet d’authentification. C’est compliqué et une librairie le fait à votre place: ADAL.

ADAL fonctionne toujours en deux temps:

  1. Création d’un AuthenticationContext
  2. Appel d’une des variantes de AcquireToken*

AuthenticationContext est simplement l’abstraction du service d’authentification.

 

Retenez aussi qu’Adal propose un cache par défaut (TokenCache). MAIS….. C’est un cache par défaut. Quel est alors le problème?

Adal est initialement arrivé pour résoudre des problèmes d’authentification pour les application natives. Le cache a donc été étudié pour ce contexte.

Ainsi:

  • Il n’est pas thread-safe
  • Il n’a pas de bonnes aptitudes à la scalabilité
  • Il ne fonctionne pas dans une ferme de serveurs faute d’être distribué

C’est pour l’essentiel un Dictionnary. Dans le contexte d’une application web, vous devrez donc probablement en écrire un perso en s’inspirant des exemples que l’on trouve un peu partout.

Par exemple pour un cache multi-tenant:

https://docs.microsoft.com/en-us/azure/architecture/multitenant-identity/token-cache

 

Divers

Comment retrouver son tenant id:

https://amethyste16.wordpress.com/2017/07/14/comment-trouver-lid-de-son-tenant/

 

Publicités

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