Spring Boot統合テストのためのSpring Security

Spring Boot統合テストのSpring Security

1. 前書き

スタンドアロンの統合環境を必要とせずに統合テストを実行する機能は、ソフトウェアスタックにとって貴重な機能です。 Spring BootとSpring Securityのシームレスな統合により、セキュリティレイヤーと対話するコンポーネントを簡単にテストできます。

このクイックチュートリアルでは、@MockMvcTest@SpringBootTestを使用してセキュリティ対応の統合テストを実行する方法について説明します。

2. 依存関係

まず、例に必要な依存関係を取り入れましょう。


    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

spring-boot-starter-webspring-boot-starter-security,およびspring-boot-starter-test starterは、Spring MVC、Spring Security、およびSpringBootテストユーティリティへのアクセスを提供します。

さらに、使用する@WithMockUserアノテーションにアクセスするために、spring-security-testを取り込みます。

3. Webセキュリティ構成

Webセキュリティ設定は簡単です。 認証されたユーザーのみが/private/に一致するパスにアクセスできます。 /public/に一致するパスは、すべてのユーザーが使用できます。

@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. メソッドのセキュリティ構成

WebSecurityConfigurer,で定義したURLパスベースのセキュリティに加えて、追加の構成ファイルを提供することにより、メソッドベースのセキュリティを構成できます。

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

この構成により、SpringSecurityの事前/事後注釈のサポートが有効になります。 追加のサポートが必要な場合は、他の属性も利用できます。 Springメソッドセキュリティの詳細については、article on the topicをご覧ください。

5. @WebMvcTestを使用したコントローラーのテスト

Spring Securityで@WebMvcTestアノテーションアプローチを使用する場合、セキュリティ構成をテストするためにMockMvc is automatically configured with the necessary filter chain が必要です。

MockMvcが構成されているため、追加の構成なしでテストに@WithMockUserを使用できます。

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

@WebMvcTestを使用すると、コンテキスト全体ではなくWebレイヤーのみをインスタンス化するようにSpringBootに指示されることに注意してください。 このため、controller tests that use @WebMvcTest will run faster than with other approaches

6. @SpringBootTestを使用したコントローラーのテスト

@SpringBootTestアノテーションを使用してSpring Securityでコントローラーをテストする場合、it’s necessary to explicitly configure the filter chain when setting up MockMvc

これを行うには、SecurityMockMvcConfigurerが提供する静的なspringSecurityメソッドを使用することをお勧めします。

@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. @SpringBootTestを使用したセキュリティで保護されたメソッドのテスト

@SpringBootTestは、セキュリティで保護されたメソッドをテストするために追加の構成を必要としません。 simply 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. @SpringBootTestおよびTestRestTemplateを使用したテスト

TestRestTemplateは、セキュリティで保護されたRESTエンドポイントの統合テストを作成するときに便利なオプションです。

simply 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は柔軟性があり、多くの便利なセキュリティ関連オプションを提供します。 TestRestTemplateの詳細については、article on the topicを確認してください。

9. 結論

この記事では、セキュリティ対応の統合テストを実行するいくつかの方法を検討しました。

mvccontrollerおよびRESTエンドポイント、およびセキュリティで保護されたメソッドの使用方法を検討しました。

いつものように、ここの例のすべてのソースコードはfound over on GitHubにすることができます。