Plusieurs fournisseurs d'authentification dans Spring Security

1. Vue d'ensemble

Dans cet article rapide, nous allons nous concentrer sur l'utilisation de plusieurs mécanismes pour authentifier les utilisateurs dans Spring Security.

Nous le ferons en configurant plusieurs fournisseurs d'authentification.

2. Fournisseurs d'authentification

Un AuthenticationProvider est une abstraction pour récupérer les informations utilisateur à partir d'un référentiel spécifique (comme une base de données, LDAP, une source tierce personnalisée, etc.). Il utilise les informations utilisateur extraites pour valider les informations d'identification fournies.

En termes simples, lorsque plusieurs fournisseurs d'authentification sont définis, les fournisseurs seront interrogés dans l'ordre dans lequel ils sont déclarés.

Pour une démonstration rapide, nous allons configurer deux fournisseurs d'authentification - un fournisseur d'authentification personnalisé et un fournisseur d'authentification en mémoire.

3. Dépendances de Maven

Ajoutons d'abord les dépendances Spring Security nécessaires dans notre application Web:

 org.springframework.boot spring-boot-starter-web   org.springframework.boot spring-boot-starter-security  

Et, sans Spring Boot:

 org.springframework.security spring-security-web 5.2.2.RELEASE   org.springframework.security spring-security-core 5.2.2.RELEASE   org.springframework.security spring-security-config 5.2.2.RELEASE 

La dernière version de ces dépendances se trouve sur spring-security-web, spring-security-core et spring-security-config.

4. Fournisseur d'authentification personnalisé

Créons maintenant un fournisseur d'authentification personnalisé en implémentant l' interface AuthneticationProvider .

Nous allons implémenter la méthode authenticate - qui tente l'authentification. L' objet d' authentification d' entrée contient le nom d'utilisateur et le mot de passe fournis par l'utilisateur.

La méthode authenticate renvoie un objet Authentication entièrement rempli si l'authentification réussit. Si l'authentification échoue, elle lève une exception de type AuthenticationException :

@Component public class CustomAuthenticationProvider implements AuthenticationProvider { @Override public Authentication authenticate(Authentication auth) throws AuthenticationException { String username = auth.getName(); String password = auth.getCredentials() .toString(); if ("externaluser".equals(username) && "pass".equals(password)) { return new UsernamePasswordAuthenticationToken (username, password, Collections.emptyList()); } else { throw new BadCredentialsException("External system authentication failed"); } } @Override public boolean supports(Class auth) { return auth.equals(UsernamePasswordAuthenticationToken.class); } }

Naturellement, il s'agit d'une implémentation simple aux fins de notre exemple ici.

5. Configuration de plusieurs fournisseurs d'authentification

Ajoutons maintenant le CustomAuthenticationProvider et un fournisseur d'authentification en mémoire à notre configuration Spring Security.

5.1. Configuration Java

Dans notre classe de configuration, créons et ajoutons maintenant les fournisseurs d'authentification à l'aide de AuthenticationManagerBuilder .

Tout d'abord, le CustomAuthenticationProvider , puis un fournisseur d'authentification en mémoire à l'aide de inMemoryAuthentication () .

Nous nous assurons également que l'accès au modèle d'URL « / api / ** » doit être authentifié:

@EnableWebSecurity public class MultipleAuthProvidersSecurityConfig extends WebSecurityConfigurerAdapter { @Autowired CustomAuthenticationProvider customAuthProvider; @Override public void configure(AuthenticationManagerBuilder auth) throws Exception { auth.authenticationProvider(customAuthProvider); auth.inMemoryAuthentication() .withUser("memuser") .password(encoder().encode("pass")) .roles("USER"); } @Override protected void configure(HttpSecurity http) throws Exception { http.httpBasic() .and() .authorizeRequests() .antMatchers("/api/**") .authenticated(); } @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } }

5.2. Configuration XML

Alternativement, si nous voulons utiliser la configuration XML au lieu de la configuration Java:

6. L'application

Ensuite, créons un point de terminaison REST simple qui est sécurisé par nos deux fournisseurs d'authentification.

Pour accéder à ce point de terminaison, un nom d'utilisateur et un mot de passe valides doivent être fournis. Nos fournisseurs d'authentification valideront les informations d'identification et détermineront s'il faut autoriser l'accès ou non:

@RestController public class MultipleAuthController { @GetMapping("/api/ping") public String getPing() { return "OK"; } }

7. Test

Enfin, testons maintenant l'accès à notre application sécurisée. L'accès ne sera autorisé que si des informations d'identification valides sont fournies:

@Autowired private TestRestTemplate restTemplate; @Test public void givenMemUsers_whenGetPingWithValidUser_thenOk() { ResponseEntity result = makeRestCallToGetPing("memuser", "pass"); assertThat(result.getStatusCodeValue()).isEqualTo(200); assertThat(result.getBody()).isEqualTo("OK"); } @Test public void givenExternalUsers_whenGetPingWithValidUser_thenOK() { ResponseEntity result = makeRestCallToGetPing("externaluser", "pass"); assertThat(result.getStatusCodeValue()).isEqualTo(200); assertThat(result.getBody()).isEqualTo("OK"); } @Test public void givenAuthProviders_whenGetPingWithNoCred_then401() { ResponseEntity result = makeRestCallToGetPing(); assertThat(result.getStatusCodeValue()).isEqualTo(401); } @Test public void givenAuthProviders_whenGetPingWithBadCred_then401() { ResponseEntity result = makeRestCallToGetPing("user", "bad_password"); assertThat(result.getStatusCodeValue()).isEqualTo(401); } private ResponseEntity makeRestCallToGetPing(String username, String password) { return restTemplate.withBasicAuth(username, password) .getForEntity("/api/ping", String.class, Collections.emptyMap()); } private ResponseEntity makeRestCallToGetPing() { return restTemplate .getForEntity("/api/ping", String.class, Collections.emptyMap()); }

8. Conclusion

Dans ce tutoriel rapide, nous avons vu comment plusieurs fournisseurs d'authentification peuvent être configurés dans Spring Security. Nous avons sécurisé une application simple en utilisant un fournisseur d'authentification personnalisé et un fournisseur d'authentification en mémoire.

Et nous avons également écrit des tests pour vérifier que l'accès à notre application nécessite des informations d'identification qui peuvent être validées par au moins l'un de nos fournisseurs d'authentification.

Comme toujours, le code source complet de l'implémentation est disponible à l'adresse over sur GitHub.