I. Spring Security: Généralités
1. Présentation
Spring est considéré comme un terme générique qui couvre unn ensemble de framework dont Spring Security dans l’écosystème Java. Spring Security est un framework d'authentification et d'autorisation puissant qu'on peut personnaliser ( customiser). Pour sécuriser des applications basées sur Spring, on l'utilise et lorsqu'on cherche à implémenter une solution de jeton JWT, il est logique de la baser sur Spring JWT. Malgré sa popularité, Spring Security n'est pas simple et direct à configurer. Dans Spring Security des termes son utilisés et il est important de comprendre leur signification.
1.1. L'authentification
Elle fait référence au processus de vérification de l'identité d'un utilisateur, sur la base des informations d'identification fournies. Un exemple courant consiste à saisir un nom d'utilisateur et un mot de passe lorsque vous vous connectez à un site Web.
Ici vous pouvez y voir une réponse à la question "Qui êtes-vous ?" qui nécessite de donne un nom mais aussi un gage qui permet d'être sûr que c'est vraiment et c'est un mot de passe . Muni de ses informations on vérifie ( le système) que vous êtes connue et enregistré sur le système. Une fois cette reconnaissance faite il va falloir savoir quelles sont vos autorisations
1.2. L'autorisation
Elle fait référence au processus permettant de déterminer si un utilisateur dispose de l'autorisation appropriée pour effectuer une action particulière ou lire des données particulières, en supposant que l'utilisateur est authentifié avec succès. Vous pouvez y voir une réponse à la question Un utilisateur peut-il faire ?
1.3. La classe Principal
Elle fait référence à l'utilisateur actuellement authentifié.
1.4. L'autorité accordée
Elle fait référence à l'autorisation de l'utilisateur authentifié.
1.5. Le rôle
il fait référence à un groupe d'autorisations de l'utilisateur authentifié
Une fois qu'on a défini ces termes, regardons de prêt l'architecture ou plutôt comment fonctionne Spring Security. L'architecture de Spring Security est conçue de telle sorte que l'on puisse distinguer l'authentification et l'autorisation puis de pouvoir gérer des stratégies et des points d'extension pour les deux.
2. Architecture de Spring Security
Les filtres sont des composants Java enfichables qu'on utilise pour intercepter et traiter des requêtes clientes avant qu'elles ne soient envoyées aux servlets; pour une application basée sur une servlet, Le conteneur de servlets crée un objet de type FilterChain qui contient les instances des différents filtres et de la Servlet de l'application.
comme Spring est un framework basé sur une servlet en l'occurence DispatcherServlet, Si on utilise Spring Security , le système de filtres de Spring Security "Spring Security Filter Chain" est pris en charge par la chaine de filtrage du conteneur de servlets au niveau de FilterChaineProxy (voir shéma ci-dessous) par un filtre nommé DelegatingFilterProxy; celui-ci permet de faire le pont entre le cycle de vie du conteneur de servlets et ApplicationContext de Spring.
On peut enregistrer DelegatingFilterProxy via les mécanismes du conteneur de Servlet standard, mais déléguer tout le travail à un Spring Bean qui implémente Filter.
Le client envoie une requête à l'application et le conteneur crée un filtre de type FilterChain, qui contient les instances de filtres et la servlet qui doivent traiter les requêtes de type HttpServletRequest, en fonction de l'URI de la requête. Dans une application Spring MVC, le/la Servlet qui traite ces requêtes est une instance de DispatcherServlet. Tout au plus, un/une servlet peut gérer une seule requête de type HttpServletRequest et d'une reponse de type HttpServletResponse.
Spring Security ne sécurise pas les réseaux ou les ordinateurs, mais les applications: il intervient dans le dialogue entre l'application et l'utilisateur (ou entre deux applications). Ce dialogue est géré par le servlet Spring DispatcherServlet , qui redirige les requêtes http vers les classes contrôleur de l'application. En résumé, le rôle de Spring Security est d'insérer des opérations dans cette interaction, grâce à un ensemble de filtres de servlets. Ce groupe de filtres est la chaîne de filtres de Spring Security.
3. Chaîne de filtres de Spring Security
3.1. Généralités
Comme il est précisé ci-dessus, dans une application basée sur des servlets, les requêtes en entrée passent par un certain nombre de filtres; il en est de même des filtres de Spring Security. L'image suivante montre la superposition typique des gestionnaires de filtres pour une seule requête HTTP.
Avant de commencer à personnaliser la configuration, discutons d'abord du fonctionnement de l'authentification de Spring Security en coulisses. Le diagramme suivant montre que Spring Security est un ensemble de filtres; le traitement des requêtes en entrée est géré par "AuthenticationManager" ; le flux est ensuite dispatcher aux différents "AuthentificationProvider".
Lorsqu'on ajoute le framework Spring Security à une application, il enregistre automatiquement une chaîne de filtres qui interceptent toutes les requêtes entrantes. Cette chaîne se compose de différents filtres, et chacun d'entre eux gère un cas d'utilisation particulier.
Cependant, plusieurs filtres peuvent être utilisés pour par exemple :
- Empêchez l'appel des instances de filtre en aval ou certains appels du servlet. Dans ce cas, le filtre écrit généralement la réponse HttpServletResponse.
- Modifiez la requête de type HttpServletRequest ou la réponse de type HttpServletResponse utilisé par les instances de filtre en aval ou du servlet.
La puissance du filtre vient de la FilterChain qui y est transmise.
La chaîne de filtrage effectue des actions avant d'atteindre le Servlet DispatcherServlet, afin de vérifier si une requête provient d'un utilisateur authentifié et autorisé, avant de la laisser aller vers les contrôleurs. En résumé La chaîne de filtrage traite 2 concepts fondamentaux :
authentification : l'utilisateur doit être identifié par une combinaison nom d'utilisateur/mot de passe.
autorisations : les utilisateurs ne sont pas égaux quant aux opérations qu'ils sont autorisés à effectuer. A titre d'exemple, un utilisateur qui n'est pas administrateur ne doit pas être autorisé à modifier le compte d'un autre utilisateur.
3.2. Exemples d'actions traitées par les filtre:
- Vérifiez si l'URL demandée est accessible au public, en fonction de la configuration.
- En cas d'authentification basée sur la session, vérifiez si l'utilisateur est déjà authentifié dans la session en cours.
- Vérifiez si l'utilisateur est autorisé à effectuer l'action demandée, et ainsi de suite. Un détail important qu'il ne faut pas oublier c'est que tous les filtres Spring Security sont enregistrés avec un ordre de traitement; les ordres les plus bas sont les premiers invoqués. Pour certains cas d'utilisation, si on souhaite placer un filtre personnalisé devant ceux de Spring Security, on doit faire la commande. Cela peut être fait avec la configuration suivante :
spring.security.filter.order=10
Une fois que nous aurons ajouté cette configuration à notre fichier "application.properties", nous aurons de l'espace pour 10 filtres personnalisés devant les filtres de Spring Security.
3.3. Exemple
......
4. Chaîne de filtres par défaut
Lors du lancement d'une application implémentant Spring Security, l'un des premiers logs apparaissant dans la console ressemble à:
2020-02-25 10:24:27.875 INFO 11116 — — [ main] o.s.s.web.DefaultSecurityFilterChain : Création d'une chaîne de filtres : toute requête […]
Ce journal répertorie les filtres par défaut implémentés par Spring Security. Ci-après, une liste ordonnée des filtres constituant la chaîne de filtres par défaut (Spring Security v5.4.2).
WebAsyncManagerIntegrationFilter : ce type est comme le ciment entre le SecurityContext et le WebAsyncManager, permettant de remplir le SecurityContext pour chaque requête.
SecurityContextPersistenceFilter : envoie les informations du SecurityContextRepository au SecurityContextHolder, ce dernier étant nécessaire au processus d'authentification, qui nécessite un SecurityContext valide.
HeaderWriterFilter : ajoute des en-têtes à la requête en cours. Ce filtre est particulièrement utile pour prévenir certaines attaques courantes en ajoutant des en-têtes comme X-Frame-Options, X-XSS-Protection et X-Content-Type-Options (voir la partie sur la protection générale ci-dessous)
CsrfFilter : ajoute une protection contre les attaques Cross-Site Request Forgery, en impliquant un jeton, qui est généralement enregistré sous forme de cookie dans la HttpSession. Il est courant d'appeler ce filtre avant toute requête pouvant changer l'état de l'application (principalement POST, PUT, DELETE et parfois OPTIONS).
LogoutFilter : gère le processus de déconnexion en appelant plusieurs lougoutHandlers chargés d'effacer le contexte de sécurité, d'invalider la session utilisateur, de rediriger vers la page par défaut…
UsernamePasswordAuthenticationFilter : analyse la soumission d'un formulaire d'authentification, qui doit fournir un nom d'utilisateur et un mot de passe. Ce filtre est activé par défaut sur l'URL /login.
DefaultLoginPageGeneratingFilter : construit une page d'authentification par défaut, à moins qu'elle ne soit explicitement inactivée. Ce filtre est la raison pour laquelle une page de connexion apparaît lors de l'implémentation de Spring Security, avant même que le développeur n'en crée une personnalisée.
DefaultLogoutPageGeneratingFilter : construit une page de déconnexion par défaut, à moins qu'elle ne soit explicitement inactivée.
BasicAuthenticationFilter : vérifie si une demande inclut un en-tête d'authentification de base et tente de se connecter avec le nom d'utilisateur et le mot de passe lus dans cet en-tête.
RequestCacheAwareFilter : vérifie dans le cache si la requête en cours est similaire à une ancienne afin d'accélérer son traitement.
SecurityContextHolderAwareRequestFilter : offre de multiples fonctionnalités pour chaque requête, notamment concernant le processus d'authentification : récupérer les informations des utilisateurs, vérifier s'ils sont authentifiés (et sinon, offrir la possibilité de s'authentifier via le gestionnaire d'authentification), obtenir leurs rôles, proposer de se déconnecter via les gestionnaires de déconnexion, maintenant le contexte de sécurité sur plusieurs threads…
AnonymousAuthenticationFilter : fournit un objet d'authentification au détenteur du contexte de sécurité s'il n'y en a pas.
SessionManagementFilter : vérifie si un utilisateur est authentifié depuis le début de la requête, et dans ce cas, procède aux vérifications liées à la session (à titre d'exemple, vérifie si plusieurs connexions simultanées sont actuellement en cours d'utilisation).
ExceptionTranslationFilter : gérez les exceptions AccessDeniedException et AuthenticationException levées par filterChain. Ce filtre est essentiel pour que l'interface graphique reste cohérente lorsque des erreurs se produisent, car il constitue le pont entre les exceptions Java et les réponses http.
FilterSecurityInterceptor : vérifie si les rôles de l'utilisateur correspondent aux exigences d'autorisation pour la demande en cours.
........
.......