Как передать Spring SecurityContext в RestAssured - PullRequest
0 голосов
/ 10 мая 2018

Я пытаюсь настроить тест RestAssured для приложения Spring-Boot с защищенными контроллерами уровня метода.

Например, у меня есть этот минимальный контроллер, использующий метод уровня безопасности


@RestController
public class DummyController {
    @GetMapping("/")
    @PreAuthorize("hasRole('TEST')") // removing this should make the test green
    public String test() {
        return "hello";
    }
}

и разрешительная конфигурация безопасности


@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests().anyRequest().permitAll();
    }
}

Тогда этот простой тест с использованием RestAssured завершается неудачей:

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@RunWith(SpringRunner.class)
public class DummyControllerITest {
    private static final Logger logger = LoggerFactory.getLogger(DummyControllerITest.class);

    @LocalServerPort
    private int port;

    @Test
    @WithMockUser(roles = "TEST")
    public void name() throws Exception {
        RestAssured.given()
                .port(port)
            .when()
                .get("/")
            .then()
                .statusCode(HttpStatus.OK.value());
    }
}

Почему этот тест не пройден, даже если фиктивный пользователь настроен на правильную роль?

Я отладил это, и кажется, что SecurityContext в потоке, выполняющем тест, настроен правильно, в то время как SecurityContext в потоке, обрабатывающем запрос RestAssured, не заполняется. Но ... почему?

1 Ответ

0 голосов
/ 12 мая 2018

Итак, я наконец понял, что случилось. Вот что я узнал:

Внедрение SecurityContext имеет смысл только в модульных тестах, но оригинальный тест пытается быть интеграционным тестом.

Есть два выхода:

  1. Сделайте тест надлежащим модульным тестом. Тогда вы должны использовать RestAssuredMockMvc.given() вместо RestAssured.given(). Например,

    @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK)
    @RunWith(SpringRunner.class)
    public class DummyControllerITest {
      @Autowired
      private WebApplicationContext webAppContextSetup;
    
      @Test
      @WithMockUser(roles = "TEST")
      public void name() throws Exception {
          RestAssuredMockMvc.webAppContextSetup(webAppContextSetup);
          RestAssuredMockMvc.given()
              .when()
                  .get("/")
              .then()
                  .statusCode(HttpStatus.OK.value());
          RestAssuredMockMvc.reset();
      }
    }
    

    будет работать, но тогда это будет только юнит-тест.

  2. Сделать тест надлежащим интеграционным тестом. Это будет включать создание надлежащей аутентификации и настройку принципала тестового запроса таким образом, чтобы SecurityContext был заполнен по желанию производственным кодом . Переход по этому маршруту с RestAssured будет выглядеть примерно так:

    @Test
    @WithMockUser(roles = "TEST")
    public void name() throws Exception {
        given()
                .auth().basic("testuser", "password") // ######
                .port(port)
            .when()
                .get("/")
            .then()
                .statusCode(HttpStatus.OK.value());
    }
    
...