OAuth2 et OpenID Connect, une introduction douce et fonctionnelle (Part 1)
By WORMS David
17 nov. 2020
- Catégories
- Orchestration de conteneurs
- Cybersécurité
- Tags
- Go Lang
- JAMstack
- LDAP
- CNCF
- Kubernetes
- OAuth2
- OpenID Connect [plus][moins]
Ne ratez pas nos articles sur l'open source, le big data et les systèmes distribués, fréquence faible d’un email tous les deux mois.
La compréhension d’OAuth2, d’OpenID et d’OpenID Connect (OIDC), comment ils sont liés, comment les communications sont établies, comment s’architecture votre application et que faire des différents types de token (access, id et refresh), est déroutante.
Il fut un temps où la sécurisation de votre application n’était pas si compliquée à effectuer. Les utilisateurs remplissait un formulaire de connexion demandant leur nom d’utilisateur et leur mot de passe. Le serveur validait ces informations d’identification en les comparant avec celles stockées, principalement dans une base de données SQL ou un répertoire LDAP/AD. Une fois l’utilisateur authentifié, une session était maintenue avec l’aide d’un cookie stockant l’ID utilisé pour suivre et charger les informations de l’utilisateur.
Utiliser OAuth2 et OpenID Connect peut être assez simple avec une application traditionnelle. Il existe plusieurs bibliothèques et frameworks masquant les différentes étapes impliquées. Pour les utilisateurs finaux, nous sommes tous habitués à être redirigés vers un fournisseur externe, à savoir GitHub, Google, Facebook et autres. Le processus est familier et bien accepté. Cependant, cela commence à être plus compliqué lorsque vous souhaitez répliquer les étapes impliquées ou lorsque vous souhaitez créer une architecture alternative comprenant des applications mobiles, des architectures de microservices, des Single Page Applications (SPA) et des front-ends statiques comme avec le paradigme JAMstack. Les applications publiques partagent la particularité d’être non sécurisées par nature et de parler avec plusieurs serveurs API.
La partie 1, OAuth2 et OpenID Connect, une introduction douce et fonctionnelle se concentre sur l’intégration de votre première application avec le serveur OpenID Connect (Dex) et a la compréhension du Authorization Code Flow (pour flux d’autorisation par code) avec un server OAuth externe. Les stratégies Oauth et OpenID Connect sont compliquées et déroutantes, la lecture de cette première partie apportera de la lumière.
La partie 2, OAuth2 et OpenID Connect pour les microservices et les applications publiques, fournit une plongée approfondie dans la séquence OpenID Connect en décrivant, expliquant et illustrant chaque étape. Une fois terminés, vous pourrez les appliquer à vos applications clientes et publiques (mobile, SPA, …) sans avoir besoin d’outils supplémentaires.
OAuth, OAuth2, OpenID, OpenID Connect, OIDC, …
Ce n’est pas si compliqué. OpenID est un protocole d’authentification tandis que OAuth est pour l’autorisation. Avec OpenID, l’authentification est déléguée. Avec OAuth, l’autorisation est également déléguée.
OAuth est OAuth2. Personne n’utilise une telle chose comme OAuth1. OpenID Connect, également appelé OIDC, apporte les fonctionnalités d’OpenID et transforme OAuth en protocole d’authentification. Ainsi, il s’agit d’une fine couche au-dessus d’OAuth. La plupart des serveurs OAuth2 sont également des serveurs OpenID Connect.
Puisque nous parlons de délégation, nous utiliserons Dex un fournisseur OpenID Connect fédérateur. Dex peut authentifier les utilisateurs par rapport à sa base de données interne et des bases de données externes, pensez LDAP. Il peut aussi déléguer l’authentification à d’autres fournisseurs OpenID Connect, pensez GitHub, Google, … Ainsi, Dex peut agir comme une façade placée devant plusieurs fournisseurs.
Un peu d’OAuth avant de commencer
OAuth décrit les acteurs suivants : le Resource Owner (RO, le propriétaire de la ressource), le client, l’Authorisation Server (AS, le serveur d’autorisation) et le Resource Server (RS, le serveur de ressources).
Le propriétaire de la ressource est l’utilisateur final, mais il peut également s’agir de l’organisation, d’un projet ou de toute autre entité. Le client est l’application qui souhaite authentifier cet utilisateur. Cela peut être une application Web, une application mobile, … Le serveur OAuth, qui est également le serveur OpenID Connect, s’appelle le serveur d’autorisation (AS) et il est chargé de l’émission des jetons et de déterminer qui est l’utilisateur final. Enfin, il y a le serveur de ressources qui donne accès à la ressource, telle que l’API.
JWT, pour JSON Web Token, prononcé en anglais “jot”, est un format spécial utilisé par OAuth2 pour sérialiser les jetons. Ce n’est pas le seul format mais certainement le plus couramment utilisé.
Authorization Code Flow (flux avec code d’autorisation)
OAuth2 proposes plusieurs flux. Ce sont des séquences du protocole nécessaire pour authentifier ou autoriser. Il en existe encore d’avantage avec OpenID Connect. La plupart d’entre eux sont des déclinaisons légères de l’Authorization Code Flow. Tous ne sont pas aussi sécurisés et pris en charge par votre serveur OAuth.
Nous choisissons de travailler avec l’Authorization Code Flow car il est de loin le plus courant. Si vous souhaitez savoir comment l’utiliser avec une application cliente publique, lisez l’article suivant, partie 2, OAuth2 et OpenID Connect pour les microservices et les applications publiques. Il montre comment PKCE étend le flux pour éliminer la présence de la clé secrète et rendre le flux adapté aux applications publiques.
Mais d’abord, nous avons besoin d’un serveur OAuth. Nous utiliserons Dex, un service d’identité qui utilise OpenID Connect pour fédérer l’authentification avec d’autres applications. Il est livré avec des connecteurs tels que LDAP, SAML 2.0, OIDC, GitHub, Google, … Il est très léger et écrit en Go. Il fait partie de la Cloud Native Computing Foundation (CNCF) et c’est un choix populaire avec Kubernetes.
L’installation à partir des sources est assez simple, en supposant que go
soit installé sur votre hôte :
git clone https://github.com/dexidp/dex.git
cd dex
make build
Le serveur est livré avec une configuration prédéfinie située dans le dossier “examples/config-dev.yaml”. Nous le référencerons pour démarrer le serveur :
./bin/dex serve examples/config-dev.yaml
La configuration définit un exemple d’application cliente avec ses propriétés id
et secret
.
staticClients:
- id: example-app
redirectURIs:
- 'http://127.0.0.1:5555/callback'
name: 'Example App'
secret: ZXhhbXBsZS1hcHAtc2VjcmV0
Cette configuration est conçue pour correspondre aux paramètres de l’application cliente dans le dossier “examples/example-app”. Vous pouvez la démarrer ainsi :
make examples
./bin/example-app
Dex fédère plusieurs fournisseurs d’authentification et il est également livré avec un stockage interne par défaut. Dans la configuration utilisée, ce stockage est configuré avec un seul utilisateur dont l’email et le mot de passe sont admin@example.com
et password
.
Naviguez dans l’exemple en vous rendant avec votre navigateur sur http://localhost:5555/
. Appuyez sur “Login”, choisissez “Login with email” et utilisez ces informations de l’utilisateur admin@example.com
. Une fois terminé, vous verrez le jeton fourni par DEX ainsi que ses claims qui sont des propriétés.
Vous venez de faire l’expérience de la séquence nommée Authorization Code Flow. Le client a demandé à l’utilisateur de valider son identité (inscription, login, …). Il est redirigé vers l’Authorisation Server qui lui demande de se connecter. Cette étape peut être transparente, par exemple l’utilisateur est déjà connecté, demander un nom d’utilisateur et un mot de passe et même utiliser une authentification à 2 facteurs (two-factor authentication, 2FA). Une fois authentifié, le serveur d’applications demande le consentement. Il autorise l’application cliente à accéder aux ressources en votre nom. Cette étape est également facultative.
Utilisation d’un fournisseur externe
Nous allons maintenant activer le fournisseur GitHub dans Dex. Il est fort probable que tous ceux qui liront cet article jusqu’à la fin aient un compte GitHub. Sinon, créez un compte ou ajustez ces instructions en fonction d’un connecteur de votre choix, telles que Google. Connectez-vous à votre compte GitHub, accédez à register a new OAuth application et saisissez les attributs suivants :
- Application name :
Dex Example
- Homepage URL :
http://127.0.0.1:5556/dex/
- Authorization callback URL :
http://127.0.0.1:5556/dex/callback
Dans l’écran suivant, générez un nouveau secret client, importez-le dans votre configuration Dex ainsi que l’ID client qui s’affiche. Dans “examples/config-dev.yaml”, dans la section connectors
, ajoutez :
- type: github
# Required field for connector id.
id: github
# Required field for connector name.
name: GitHub
config:
# Credentials can be string literals or pulled from the environment.
clientID: 07e429328dXXXXXXXXXX
clientSecret: a376ab209ea2e1127bcdcc63e06672XXXXXXXXXX
redirectURI: http://127.0.0.1:5556/dex/callback
Maintenant, redémarrez le serveur Dex, connectez-vous et choisissez “Connexion avec GitHub”.
Une fois authentifié, une page affiche le contenu de votre JWT. En complément, un email de GitHub a été envoyé. Le message est le suivant :
Hey {username} !
A third-party OAuth application ({application name}) with user:email scope was recently authorized to access your account.
Visit https://github.com/settings/connections/applications/{clientID} for more information.To see this and other security events for your account, visit https://github.com/settings/security-log
If you run into problems, please contact support by visiting https://github.com/contact
Thanks,
The GitHub Team
Conclusion
Vous venez d’intégrer votre première application à un serveur OpenID Connect. Plus exactement deux serveurs. Votre application client se connecte au serveur OAuth de Dex qui lui-même est un client vers le serveur OAuth de GitHub. Vous avez aussi découvert la séquence nommée Authorization Code Flow. Dans l’article suivant, OAuth2 et OpenID Connect pour les microservices et les applications publiques (Partie 2), nous allons entrer plus en détail, expliquer et illustrer chaque étape de la séquence afin de les comprendre et de les reproduire dans votre code. L’article décrira également PKCE, une petite extension de l’Authorization Code Flow, qui supprime l’utilisation de la clé secrète et la rend le protocole approprié à une application publique.