Spring Security für Spring Boot-Integrationstests

Spring Security für Spring Boot Integrationstests

1. Einführung

Die Möglichkeit, Integrationstests auszuführen, ohne dass eine eigenständige Integrationsumgebung erforderlich ist, ist eine wertvolle Funktion für jeden Software-Stack. Die nahtlose Integration von Spring Boot in Spring Security erleichtert das Testen von Komponenten, die mit einer Sicherheitsebene interagieren.

In diesem kurzen Tutorial werden wir die Verwendung von@MockMvcTest und@SpringBootTest untersuchen, um sicherheitsfähige Integrationstests auszuführen.

2. Abhängigkeiten

Lassen Sie uns zunächst die Abhängigkeiten einbringen, die wir für unser Beispiel benötigen:


    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

Die Starterspring-boot-starter-webspring-boot-starter-security, undspring-boot-starter-test bieten uns Zugriff auf Spring MVC, Spring Security und die Spring Boot-Testdienstprogramme.

Außerdem bringen wirspring-security-test ein, um Zugriff auf die Annotation von@WithMockUserzu erhalten, die wir verwenden werden.

3. Web-Sicherheitskonfiguration

Unsere Web-Sicherheitskonfiguration ist unkompliziert. Nur authentifizierte Benutzer können auf Pfade zugreifen, die mit/private/ übereinstimmen. Pfade, die mit/public/ übereinstimmen, stehen jedem Benutzer zur Verfügung:

@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. Methodensicherheitskonfiguration

Zusätzlich zu der in unserenWebSecurityConfigurer, definierten URL-Pfad-basierten Sicherheit können wir die methodenbasierte Sicherheit konfigurieren, indem wir eine zusätzliche Konfigurationsdatei bereitstellen:

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

Diese Konfiguration ermöglicht die Unterstützung der Pre / Post-Annotationen von Spring Security. Andere Attribute sind ebenfalls verfügbar, wenn zusätzliche Unterstützung erforderlich ist. Weitere Informationen zur Sicherheit von Spring-Methoden finden Sie in unserenarticle on the topic.

5. Testen von Controllern mit@WebMvcTest

Bei Verwendung des Annotationsansatzes von@WebMvcTestmit Spring Security warMockMvc is automatically configured with the necessary filter chain erforderlich, um unsere Sicherheitskonfiguration zu testen.

DaMockMvc für uns konfiguriert ist, können wir@WithMockUser für unsere Tests ohne zusätzliche Konfiguration verwenden:

@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());
    }
}

Beachten Sie, dass die Verwendung von@WebMvcTest Spring Boot anweist, nur die Webebene und nicht den gesamten Kontext zu instanziieren. Aus diesem Grund istcontroller tests that use @WebMvcTest will run faster than with other approaches.

6. Testen von Controllern mit@SpringBootTest

Wenn Sie die Annotation@SpringBootTest verwenden, um Controller mit Spring Security zu testen,it’s necessary to explicitly configure the filter chain when setting up MockMvc.

Die Verwendung der statischenspringSecurity-Methode vonSecurityMockMvcConfigurer ist der bevorzugte Weg, um dies zu tun:

@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. Testen gesicherter Methoden mit@SpringBootTest

@SpringBootTest erfordert keine zusätzliche Konfiguration, um gesicherte Methoden zu testen. Wir könnensimply 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. Testen mit@SpringBootTest undTestRestTemplate

TestRestTemplate ist eine praktische Option beim Schreiben von Integrationstests für gesicherte REST-Endpunkte.

Wir könnensimply 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 ist flexibel und bietet viele nützliche sicherheitsrelevante Optionen. Weitere Informationen zuTestRestTemplate finden Sie in unserenarticle on the topic.

9. Fazit

In diesem Artikel haben wir uns mit verschiedenen Methoden zum Ausführen von Integrationstests mit aktivierter Sicherheit befasst.

Wir haben uns angesehen, wie man mit mvccontroller und REST-Endpunkten sowie mit gesicherten Methoden arbeitet.

Wie üblich kann der gesamte Quellcode für das Beispiel hierfound over on GitHub sein.