Spring Security pour les tests d’intégration Spring Boot

Sécurité Spring pour les tests d'intégration Spring Boot

1. introduction

La possibilité d'exécuter des tests d'intégration sans recourir à un environnement d'intégration autonome est une fonctionnalité intéressante pour toute pile de logiciels. L'intégration transparente de Spring Boot avec Spring Security facilite le test des composants qui interagissent avec une couche de sécurité.

Dans ce rapide didacticiel, nous allons explorer l'utilisation de@MockMvcTest et@SpringBootTest pour exécuter des tests d'intégration prenant en charge la sécurité.

2. Les dépendances

Commençons par introduire les dépendances dont nous aurons besoin pour notre exemple:


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


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


    org.springframework.boot
    spring-boot-starter-test
    test


    org.springframework.security
    spring-security-test
    test

Les démarreursspring-boot-starter-webspring-boot-starter-security, etspring-boot-starter-test nous donnent accès à Spring MVC, Spring Security et les utilitaires de test Spring Boot.

De plus, nous allons introduirespring-security-test afin d’accéder à l’annotation@WithMockUser que nous utiliserons.

3. Configuration de la sécurité Web

Notre configuration de sécurité Web sera simple. Seuls les utilisateurs authentifiés pourront accéder aux chemins correspondant à/private/. Les chemins qui correspondent à/public/ seront disponibles pour tous les utilisateurs:

@Configuration
public class WebSecurityConfigurer extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        PasswordEncoder encoder = PasswordEncoderFactories.createDelegatingPasswordEncoder();
        auth.inMemoryAuthentication()
         .passwordEncoder(encoder)
         .withUser("spring")
         .password(encoder.encode("secret"))
         .roles("USER");
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
          .antMatchers("/private/**")
          .authenticated()
          .antMatchers("/public/**")
          .permitAll()
          .and()
          .httpBasic();
    }
}

4. Configuration de la sécurité de la méthode

En plus de la sécurité basée sur le chemin de l'URL que nous avons définie dans nosWebSecurityConfigurer,, nous pouvons configurer la sécurité basée sur la méthode en fournissant un fichier de configuration supplémentaire:

@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class MethodSecurityConfigurer
  extends GlobalMethodSecurityConfiguration {
}

Cette configuration permet la prise en charge des annotations pré / post de Spring Security. D'autres attributs sont également disponibles si une assistance supplémentaire est requise. Pour plus d'informations sur Spring Method Security, jetez un œil à nosarticle on the topic.

5. Test des contrôleurs avec@WebMvcTest

Lorsque vous utilisez l'approche d'annotation@WebMvcTest avec Spring Security,MockMvc is automatically configured with the necessary filter chain est requis pour tester notre configuration de sécurité.

Étant donné queMockMvc est configuré pour nous, nous pouvons utiliser@WithMockUser pour nos tests sans aucune configuration supplémentaire:

@RunWith(SpringRunner.class)
@WebMvcTest(SecuredController.class)
public class SecuredControllerWebMvcIntegrationTest {

    @Autowired
    private MockMvc mvc;

    // ... other methods

    @WithMockUser(value = "spring")
    @Test
    public void givenAuthRequestOnPrivateService_shouldSucceedWith200() throws Exception {
        mvc.perform(get("/private/hello").contentType(MediaType.APPLICATION_JSON))
          .andExpect(status().isOk());
    }
}

Notez que l'utilisation de@WebMvcTest indiquera à Spring Boot d'instancier uniquement la couche Web et non l'ensemble du contexte. Pour cette raison,controller tests that use @WebMvcTest will run faster than with other approaches.

6. Test des contrôleurs avec@SpringBootTest

Lorsque vous utilisez l'annotation@SpringBootTest pour tester les contrôleurs avec Spring Security,it’s necessary to explicitly configure the filter chain when setting up MockMvc.

L'utilisation de la méthode statiquespringSecurity fournie parSecurityMockMvcConfigurer est la meilleure façon de procéder:

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
public class SecuredControllerSpringBootIntegrationTest {

    @Autowired
    private WebApplicationContext context;

    private MockMvc mvc;

    @Before
    public void setup() {
        mvc = MockMvcBuilders
          .webAppContextSetup(context)
          .apply(springSecurity())
          .build();
    }

    // ... other methods

    @WithMockUser("spring")
    @Test
    public void givenAuthRequestOnPrivateService_shouldSucceedWith200() throws Exception {
        mvc.perform(get("/private/hello").contentType(MediaType.APPLICATION_JSON))
          .andExpect(status().isOk());
    }
}

7. Test des méthodes sécurisées avec@SpringBootTest

@SpringBootTest ne nécessite aucune configuration supplémentaire pour tester les méthodes sécurisées. On peutsimply call the methods directly and use @WithMockUser as needed:

@RunWith(SpringRunner.class)
@SpringBootTest
public class SecuredMethodSpringBootIntegrationTest {

    @Autowired
    private SecuredService service;

    @Test(expected = AuthenticationCredentialsNotFoundException.class)
    public void givenUnauthenticated_whenCallService_thenThrowsException() {
        service.sayHelloSecured();
    }

    @WithMockUser(username="spring")
    @Test
    public void givenAuthenticated_whenCallServiceWithSecured_thenOk() {
        assertThat(service.sayHelloSecured()).isNotBlank();
    }
}

8. Test avec@SpringBootTest etTestRestTemplate

TestRestTemplate est une option pratique lors de l'écriture de tests d'intégration pour les points de terminaison REST sécurisés.

On peutsimply autowire a template and set credentials before requesting secured endpoints:

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
public class SecuredControllerRestTemplateIntegrationTest {

    @Autowired
    private TestRestTemplate template;

    // ... other methods

    @Test
    public void givenAuthRequestOnPrivateService_shouldSucceedWith200() throws Exception {
        ResponseEntity result = template.withBasicAuth("spring", "secret")
          .getForEntity("/private/hello", String.class);
        assertEquals(HttpStatus.OK, result.getStatusCode());
    }
}

TestRestTemplate est flexible et offre de nombreuses options utiles liées à la sécurité. Pour plus de détails sur lesTestRestTemplate, consultez nosarticle on the topic.

9. Conclusion

Dans cet article, nous avons examiné plusieurs manières d'exécuter des tests d'intégration avec sécurité.

Nous avons étudié comment utiliser les points de terminaison mvccontroller et REST, ainsi que les méthodes sécurisées.

Comme d'habitude, tout le code source de l'exemple ici peut êtrefound over on GitHub.