Как проверить безопасность сервера ресурсов spring-security-oauth2?

После выпуска Spring Security 4 и его улучшенной поддержки тестирования я захотел обновить текущие тесты сервера ресурсов Spring security oauth2.

В настоящее время у меня есть вспомогательный класс, который устанавливает OAuth2RestTemplate с помощью ResourceOwnerPasswordResourceDetails с тестом ClientId подключение к фактическому AccessTokenUri запрашивает действительный токен для моих тестов. Этот шаблон используется для отправки запросов в мой @WebIntegrationTests.

Я бы хотел отказаться от зависимости от фактического AuthorizationServer и использования действительных (если ограниченных) учетных данных пользователя в моих тестах, воспользовавшись новой поддержкой тестирования в Spring Security 4.

До сих пор все мои попытки использования @WithMockUser, @WithSecurityContext, SecurityMockMvcConfigurers.springSecurity() & SecurityMockMvcRequestPostProcessors.* не удалось сделать аутентифицированные звонки через MockMvcи я не могу найти такие рабочие примеры в проектах примеров Spring.

Может ли кто-нибудь помочь мне протестировать сервер ресурсов oauth2 с какими-то поддельными учетными данными, в то же время проверяя введенные ограничения безопасности?

** РЕДАКТИРОВАТЬ ** Пример кода доступен здесь: https://github.com/timtebeek/resource-server-testing Для каждого из тестовых классов я понимаю, почему он не будет работать, но я ищу способы, которые позволил бы мне легко проверить настройки безопасности.

Я сейчас думаю о создании очень разрешающего OAuthServer под src/test/java, что может помочь немного. У кого-нибудь есть другие предложения?

8 ответов

Решение

Для эффективного тестирования безопасности сервера ресурсов, как с MockMvc и RestTemplate это помогает настроить AuthorizationServer под src/test/java:

AuthorizationServer

@Configuration
@EnableAuthorizationServer
@SuppressWarnings("static-method")
class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
    @Bean
    public JwtAccessTokenConverter accessTokenConverter() throws Exception {
        JwtAccessTokenConverter jwt = new JwtAccessTokenConverter();
        jwt.setSigningKey(SecurityConfig.key("rsa"));
        jwt.setVerifierKey(SecurityConfig.key("rsa.pub"));
        jwt.afterPropertiesSet();
        return jwt;
    }

    @Autowired
    private AuthenticationManager   authenticationManager;

    @Override
    public void configure(final AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints
        .authenticationManager(authenticationManager)
        .accessTokenConverter(accessTokenConverter());
    }

    @Override
    public void configure(final ClientDetailsServiceConfigurer clients) throws Exception {
        clients.inMemory()
        .withClient("myclientwith")
        .authorizedGrantTypes("password")
        .authorities("myauthorities")
        .resourceIds("myresource")
        .scopes("myscope")

        .and()
        .withClient("myclientwithout")
        .authorizedGrantTypes("password")
        .authorities("myauthorities")
        .resourceIds("myresource")
        .scopes(UUID.randomUUID().toString());
    }
}

Интеграционный тест
Для интеграционных тестов можно просто использовать встроенное правило поддержки тестов OAuth2 и аннотации:

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = MyApp.class)
@WebIntegrationTest(randomPort = true)
@OAuth2ContextConfiguration(MyDetails.class)
public class MyControllerIT implements RestTemplateHolder {
    @Value("http://localhost:${local.server.port}")
    @Getter
    String                      host;

    @Getter
    @Setter
    RestOperations              restTemplate    = new TestRestTemplate();

    @Rule
    public OAuth2ContextSetup   context         = OAuth2ContextSetup.standard(this);

    @Test
    public void testHelloOAuth2WithRole() {
        ResponseEntity<String> entity = getRestTemplate().getForEntity(host + "/hello", String.class);
        assertTrue(entity.getStatusCode().is2xxSuccessful());
    }
}

class MyDetails extends ResourceOwnerPasswordResourceDetails {
    public MyDetails(final Object obj) {
        MyControllerIT it = (MyControllerIT) obj;
        setAccessTokenUri(it.getHost() + "/oauth/token");
        setClientId("myclientwith");
        setUsername("user");
        setPassword("password");
    }
}

Тест MockMvc
Тестирование с MockMvc также возможно, но нуждается в небольшом вспомогательном классе, чтобы получить RequestPostProcessor который устанавливает Authorization: Bearer <token> заголовок по запросам:

@Component
public class OAuthHelper {
    // For use with MockMvc
    public RequestPostProcessor bearerToken(final String clientid) {
        return mockRequest -> {
            OAuth2AccessToken token = createAccessToken(clientid);
            mockRequest.addHeader("Authorization", "Bearer " + token.getValue());
            return mockRequest;
        };
    }

    @Autowired
    ClientDetailsService                clientDetailsService;
    @Autowired
    AuthorizationServerTokenServices    tokenservice;

    OAuth2AccessToken createAccessToken(final String clientId) {
        // Look up authorities, resourceIds and scopes based on clientId
        ClientDetails client = clientDetailsService.loadClientByClientId(clientId);
        Collection<GrantedAuthority> authorities = client.getAuthorities();
        Set<String> resourceIds = client.getResourceIds();
        Set<String> scopes = client.getScope();

        // Default values for other parameters
        Map<String, String> requestParameters = Collections.emptyMap();
        boolean approved = true;
        String redirectUrl = null;
        Set<String> responseTypes = Collections.emptySet();
        Map<String, Serializable> extensionProperties = Collections.emptyMap();

        // Create request
        OAuth2Request oAuth2Request = new OAuth2Request(requestParameters, clientId, authorities, approved, scopes,
                resourceIds, redirectUrl, responseTypes, extensionProperties);

        // Create OAuth2AccessToken
        User userPrincipal = new User("user", "", true, true, true, true, authorities);
        UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(userPrincipal, null, authorities);
        OAuth2Authentication auth = new OAuth2Authentication(oAuth2Request, authenticationToken);
        return tokenservice.createAccessToken(auth);
    }
}

Ваш MockMvc тесты должны затем получить RequestPostProcessor от OauthHelper Класс и передать его при выполнении запросов:

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = MyApp.class)
@WebAppConfiguration
public class MyControllerTest {
    @Autowired
    private WebApplicationContext   webapp;

    private MockMvc                 mvc;

    @Before
    public void before() {
        mvc = MockMvcBuilders.webAppContextSetup(webapp)
                .apply(springSecurity())
                .alwaysDo(print())
                .build();
    }

    @Autowired
    private OAuthHelper helper;

    @Test
    public void testHelloWithRole() throws Exception {
        RequestPostProcessor bearerToken = helper.bearerToken("myclientwith");
        mvc.perform(get("/hello").with(bearerToken)).andExpect(status().isOk());
    }

    @Test
    public void testHelloWithoutRole() throws Exception {
        RequestPostProcessor bearerToken = helper.bearerToken("myclientwithout");
        mvc.perform(get("/hello").with(bearerToken)).andExpect(status().isForbidden());
    }
}

Полный пример проекта доступен на GitHub:
https://github.com/timtebeek/resource-server-testing

Я нашел намного более простой способ сделать это в следующих инструкциях, которые я прочитал здесь: http://docs.spring.io/spring-security/site/docs/4.0.x/reference/htmlsingle/. Это решение специально для тестирования @PreAuthorize с #oauth2.hasScope но я уверен, что это может быть адаптировано и для других ситуаций.

Я создаю аннотацию, которая может быть применена к @Tests:

WithMockOAuth2Scope

import org.springframework.security.test.context.support.WithSecurityContext;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@Retention(RetentionPolicy.RUNTIME)
@WithSecurityContext(factory = WithMockOAuth2ScopeSecurityContextFactory.class)
public @interface WithMockOAuth2Scope {

    String scope() default "";
}

WithMockOAuth2ScopeSecurityContextFactory

import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.OAuth2Request;
import org.springframework.security.test.context.support.WithSecurityContextFactory;

import java.util.HashSet;
import java.util.Set;

public class WithMockOAuth2ScopeSecurityContextFactory implements WithSecurityContextFactory<WithMockOAuth2Scope> {

    @Override
    public SecurityContext createSecurityContext(WithMockOAuth2Scope mockOAuth2Scope) {
        SecurityContext context = SecurityContextHolder.createEmptyContext();

        Set<String> scope = new HashSet<>();
        scope.add(mockOAuth2Scope.scope());

        OAuth2Request request = new OAuth2Request(null, null, null, true, scope, null, null, null, null);

        Authentication auth = new OAuth2Authentication(request, null);

        context.setAuthentication(auth);

        return context;
    }
}

Пример теста с использованием MockMvc:

@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest
public class LoadScheduleControllerTest {

    private MockMvc mockMvc;

    @Autowired
    LoadScheduleController loadScheduleController;

    @Before
    public void setup() {
        mockMvc = MockMvcBuilders.standaloneSetup(loadScheduleController)
                    .build();
    }

    @Test
    @WithMockOAuth2Scope(scope = "dataLicense")
    public void testSchedule() throws Exception {
        mockMvc.perform(post("/schedule").contentType(MediaType.APPLICATION_JSON_UTF8).content(json)).andDo(print());
    }
}

И это тестируемый контроллер:

@RequestMapping(value = "/schedule", method = RequestMethod.POST)
@PreAuthorize("#oauth2.hasScope('dataLicense')")
public int schedule() {
    return 0;
}

Spring Boot 1.5 представил тестовые срезы, такие как @WebMvcTest, Используя эти тестовые срезы и вручную загрузить OAuth2AutoConfiguration дает вашим тестам меньше шаблонов, и они будут работать быстрее, чем предложено @SpringBootTest основанные решения. Если вы также импортируете свою производственную конфигурацию безопасности, вы можете проверить, что настроенные цепочки фильтров работают для ваших веб-сервисов.

Вот установка вместе с некоторыми дополнительными классами, которые вы, вероятно, найдете полезными:

Контроллер:

@RestController
@RequestMapping(BookingController.API_URL)
public class BookingController {

    public static final String API_URL = "/v1/booking";

    @Autowired
    private BookingRepository bookingRepository;

    @PreAuthorize("#oauth2.hasScope('myapi:write')")
    @PatchMapping(consumes = APPLICATION_JSON_UTF8_VALUE, produces = APPLICATION_JSON_UTF8_VALUE)
    public Booking patchBooking(OAuth2Authentication authentication, @RequestBody @Valid Booking booking) {
        String subjectId = MyOAuth2Helper.subjectId(authentication);
        booking.setSubjectId(subjectId);
        return bookingRepository.save(booking);
    }
}

Тест:

@RunWith(SpringRunner.class)
@AutoConfigureJsonTesters
@WebMvcTest
@Import(DefaultTestConfiguration.class)
public class BookingControllerTest {

    @Autowired
    private MockMvc mvc;

    @Autowired
    private JacksonTester<Booking> json;

    @MockBean
    private BookingRepository bookingRepository;

    @MockBean
    public ResourceServerTokenServices resourceServerTokenServices;

    @Before
    public void setUp() throws Exception {
        // Stub the remote call that loads the authentication object
        when(resourceServerTokenServices.loadAuthentication(anyString())).thenAnswer(invocation -> SecurityContextHolder.getContext().getAuthentication());
    }

    @Test
    @WithOAuthSubject(scopes = {"myapi:read", "myapi:write"})
    public void mustHaveValidBookingForPatch() throws Exception {
        mvc.perform(patch(API_URL)
            .header(AUTHORIZATION, "Bearer foo")
            .content(json.write(new Booking("myguid", "aes")).getJson())
            .contentType(MediaType.APPLICATION_JSON_UTF8)
        ).andExpect(status().is2xxSuccessful());
    }
}

DefaultTestConfiguration:

@TestConfiguration
@Import({MySecurityConfig.class, OAuth2AutoConfiguration.class})
public class DefaultTestConfiguration {

}

MySecurityConfig (это для производства):

@Configuration
@EnableOAuth2Client
@EnableResourceServer
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .authorizeRequests()
            .antMatchers("/v1/**").authenticated();
    }

}

Пользовательская аннотация для ввода областей из тестов:

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@WithSecurityContext(factory = WithOAuthSubjectSecurityContextFactory.class)
public @interface WithOAuthSubject {

    String[] scopes() default {"myapi:write", "myapi:read"};

    String subjectId() default "a1de7cc9-1b3a-4ecd-96fa-dab6059ccf6f";

}

Фабричный класс для обработки пользовательской аннотации:

public class WithOAuthSubjectSecurityContextFactory implements WithSecurityContextFactory<WithOAuthSubject> {

    private DefaultAccessTokenConverter defaultAccessTokenConverter = new DefaultAccessTokenConverter();

    @Override
    public SecurityContext createSecurityContext(WithOAuthSubject withOAuthSubject) {
        SecurityContext context = SecurityContextHolder.createEmptyContext();

        // Copy of response from https://myidentityserver.com/identity/connect/accesstokenvalidation
        Map<String, ?> remoteToken = ImmutableMap.<String, Object>builder()
            .put("iss", "https://myfakeidentity.example.com/identity")
            .put("aud", "oauth2-resource")
            .put("exp", OffsetDateTime.now().plusDays(1L).toEpochSecond() + "")
            .put("nbf", OffsetDateTime.now().plusDays(1L).toEpochSecond() + "")
            .put("client_id", "my-client-id")
            .put("scope", Arrays.asList(withOAuthSubject.scopes()))
            .put("sub", withOAuthSubject.subjectId())
            .put("auth_time", OffsetDateTime.now().toEpochSecond() + "")
            .put("idp", "idsrv")
            .put("amr", "password")
            .build();

        OAuth2Authentication authentication = defaultAccessTokenConverter.extractAuthentication(remoteToken);
        context.setAuthentication(authentication);
        return context;
    }
}

Я использую копию ответа от нашего сервера идентификации для создания реалистичного OAuth2Authentication, Вы можете, вероятно, просто скопировать мой код. Если вы хотите повторить процесс для вашего сервера идентификации, установите точку останова в org.springframework.security.oauth2.provider.token.RemoteTokenServices#loadAuthentication или же org.springframework.boot.autoconfigure.security.oauth2.resource.UserInfoTokenServices#extractAuthenticationв зависимости от того, настроили ли вы ResourceServerTokenServices или нет.

У меня есть другое решение для этого. Увидеть ниже.

@RunWith(SpringRunner.class)
@SpringBootTest
@WebAppConfiguration
@ActiveProfiles("test")
public class AccountContollerTest {

    public static Logger log =  LoggerFactory.getLogger(AccountContollerTest.class);


    @Autowired
    private WebApplicationContext webApplicationContext;

    private MockMvc mvc;

    @Autowired
    FilterChainProxy springSecurityFilterChain;

    @Autowired
    UserRepository users;

    @Autowired
    PasswordEncoder passwordEncoder;

    @Autowired
    CustomClientDetailsService clientDetialsService;

    @Before
    public void setUp() {
         mvc = MockMvcBuilders
                 .webAppContextSetup(webApplicationContext)
                 .apply(springSecurity(springSecurityFilterChain))
                 .build();

         BaseClientDetails testClient = new ClientBuilder("testclient")
                    .secret("testclientsecret")
                    .authorizedGrantTypes("password")
                    .scopes("read", "wirte")
                    .autoApprove(true)
                    .build();

         clientDetialsService.addClient(testClient);

         User user = createDefaultUser("testuser", passwordEncoder.encode("testpassword"), "max", "Mustermann", new Email("myemail@test.de"));

         users.deleteAll();
         users.save(user);

    }

    @Test
    public void shouldRetriveAccountDetailsWithValidAccessToken() throws Exception {
        mvc.perform(get("/api/me")
                .header("Authorization", "Bearer " + validAccessToken())
                .accept(MediaType.APPLICATION_JSON))
                .andExpect(status().isOk())
                .andDo(print())
                .andExpect(jsonPath("$.userAuthentication.name").value("testuser"))
                .andExpect(jsonPath("$.authorities[0].authority").value("ROLE_USER"));
    }

    @Test
    public void shouldReciveHTTPStatusUnauthenticatedWithoutAuthorizationHeader() throws Exception{
        mvc.perform(get("/api/me")
                .accept(MediaType.APPLICATION_JSON))
                .andDo(print())
                .andExpect(status().isUnauthorized());
    }

    private String validAccessToken() throws Exception {  
        String username = "testuser";
        String password = "testpassword";

        MockHttpServletResponse response = mvc
            .perform(post("/oauth/token")
                    .header("Authorization", "Basic "
                           + new String(Base64Utils.encode(("testclient:testclientsecret")
                            .getBytes())))
                    .param("username", username)
                    .param("password", password)
                    .param("grant_type", "password"))
            .andDo(print())
            .andReturn().getResponse();

    return new ObjectMapper()
            .readValue(response.getContentAsByteArray(), OAuthToken.class)
            .accessToken;
    }

    @JsonIgnoreProperties(ignoreUnknown = true)
    private static class OAuthToken {
        @JsonProperty("access_token")
        public String accessToken;
    }
}

Надеюсь, это поможет!

Есть альтернативный подход, который я считаю чище и более значимым.

Подход заключается в том, чтобы автоматически связать хранилище токенов, а затем добавить тестовый токен, который затем может использоваться оставшимся клиентом.

Пример теста:

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

    @Autowired
    private TestRestTemplate testRestTemplate;

    @Autowired
    private TokenStore tokenStore;

    @Before
    public void setUp() {

        final OAuth2AccessToken token = new DefaultOAuth2AccessToken("FOO");
        final ClientDetails client = new BaseClientDetails("client", null, "read", "client_credentials", "ROLE_CLIENT");
        final OAuth2Authentication authentication = new OAuth2Authentication(
                new TokenRequest(null, "client", null, "client_credentials").createOAuth2Request(client), null);

        tokenStore.storeAccessToken(token, authentication);

    }

    @Test
    public void testGivenPathUsersWhenGettingForEntityThenStatusCodeIsOk() {

        final HttpHeaders headers = new HttpHeaders();
        headers.add(HttpHeaders.AUTHORIZATION, "Bearer FOO");
        headers.setContentType(MediaType.APPLICATION_JSON);

        // Given Path Users
        final UriComponentsBuilder uri = UriComponentsBuilder.fromPath("/api/users");

        // When Getting For Entity
        final ResponseEntity<String> response = testRestTemplate.exchange(uri.build().toUri(), HttpMethod.GET,
                new HttpEntity<>(headers), String.class);

        // Then Status Code Is Ok
        assertThat(response.getStatusCode(), is(HttpStatus.OK));
    }

}

Лично я считаю, что нецелесообразно проводить модульное тестирование контроллера с включенной защитой, поскольку безопасность - это отдельный уровень для контроллера. Я хотел бы создать интеграционный тест, который тестирует все слои вместе. Однако вышеприведенный подход можно легко изменить, чтобы создать модульный тест с использованием MockMvc.

Приведенный выше код основан на тесте Spring Security, написанном Дейвом Сайером.

Обратите внимание, что этот подход предназначен для серверов ресурсов, которые совместно используют то же хранилище токенов, что и сервер авторизации. Если ваш сервер ресурсов не использует то же хранилище токенов, что и сервер авторизации, я рекомендую использовать Wiremock для макетирования HTTP-ответов.

Хорошо, я еще не смог протестировать свой автономный сервер ресурсов, защищенный токеном oauth2 JWT, используя новый @WithMockUser или связанные аннотации.

В качестве обходного пути я смог провести интеграционное тестирование безопасности моего сервера ресурсов, настроив разрешающий AuthorizationServer в src / test / java, и имея то, что определяют двух клиентов, я использую через вспомогательный класс. Это помогает мне в этом, но это не так просто, как я хотел бы протестировать различных пользователей, роли, области и т. Д.

Я предполагаю, что здесь должно быть проще реализовать мой собственный WithSecurityContextFactory это создает OAuth2Authentication вместо обычного UsernamePasswordAuthentication, Тем не менее, я еще не смог проработать детали того, как легко это настроить. Любые комментарии или предложения по настройке приветствуются.

Я нашел простой и быстрый способ тестирования сервера ресурсов безопасности Spring в любом хранилище токенов. Я мой пример @EnabledResourceServerиспользует хранилище токенов jwt.

Волшебство здесь я заменил JwtTokenStore с InMemoryTokenStore при интеграционном тесте.

@RunWith (SpringRunner.class)
@SpringBootTest (classes = {Application.class}, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@ActiveProfiles ("test")
@TestPropertySource (locations = "classpath:application.yml")
@Transactional
public class ResourceServerIntegrationTest {

@Autowired
private TokenStore tokenStore;

@Autowired
private ObjectMapper jacksonObjectMapper;

@LocalServerPort
int port;

@Configuration
protected static class PrepareTokenStore {

    @Bean
    @Primary
    public TokenStore tokenStore() {
        return new InMemoryTokenStore();
    }

}

private OAuth2AccessToken token;
private OAuth2Authentication authentication;

@Before
public void init() {

    RestAssured.port = port;

    token = new DefaultOAuth2AccessToken("FOO");
    ClientDetails client = new BaseClientDetails("client", null, "read", "client_credentials", "ROLE_READER,ROLE_CLIENT");

    // Authorities
    List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
    authorities.add(new SimpleGrantedAuthority("ROLE_READER"));
    UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken("writer", "writer", authorities);

    authentication = new OAuth2Authentication(new TokenRequest(null, "client", null, "client_credentials").createOAuth2Request(client), authenticationToken);
    tokenStore.storeAccessToken(token, authentication);

}

@Test
public void gbsUserController_findById() throws Exception {

    RestAssured.given().log().all().when().headers("Authorization", "Bearer FOO").get("/gbsusers/{id}", 2L).then().log().all().statusCode(HttpStatus.OK.value());

}

Еще одно решение я попытался достаточно подробно:-D

Он основан на настройке заголовка авторизации, как некоторые выше, но я хотел:

  • Не создавать действительные токены JWT и использовать весь стек аутентификации JWT (юнит-тесты...)
  • Тестовая аутентификация, содержащая определенные в тестовом случае области и полномочия

Итак, я:

  • создал пользовательскую аннотацию с @WithSecurityContext и завод, как некоторые другие сделали, чтобы настроить тест OAuth2Authentication (@WithJwt в моем случае)
  • @MockBean TokenStore для возврата OAuth2Authentication, настроенного с @WithJwt
  • предоставлять MockHttpServletRequestBuilder фабрики, которые устанавливают определенный заголовок авторизации, перехваченный макетом TokenStore для внедрения ожидаемой аутентификации.

PS

Не стесняйтесь принять / проголосовать за мое решение, если оно наилучшим образом соответствует вашим потребностям;-)

Я пробовал много способов. Но мое решение проще других. Я использую аутентификацию OAuth2 JWT в своем приложении весенней загрузки. Моя цель - пройти тест по контракту. Я пишу скрипт с Groovy, а плагин контракта генерирует для меня тестовые коды. Поэтому я не могу вмешиваться в коды. У меня простой класс BaseTest. Мне нужно сделать все необходимые настройки в этом классе. Это решение сработало для меня.

Импортированная зависимость:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-test</artifactId>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-contract-verifier</artifactId>
    <version>2.1.1.RELEASE</version>
    <scope>test</scope>
</dependency>

Импортированные плагины:

    <plugin>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-contract-maven-plugin</artifactId>
        <version>2.1.1.RELEASE</version>
        <extensions>true</extensions>
        <configuration>
            <baseClassForTests>com.test.services.BaseTestClass
            </baseClassForTests>
        </configuration>
    </plugin>

BaseTestClass.java

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK)
@DirtiesContext
@AutoConfigureMessageVerifier
@ContextConfiguration
@WithMockUser(username = "admin", roles = {"USER", "ADMIN"})
public class BaseTestClass {

    @Autowired
    private MyController myController;

    @Autowired
    private WebApplicationContext webApplicationContext;

    @Before
    public void setup() {
        StandaloneMockMvcBuilder standaloneMockMvcBuilder = MockMvcBuilders.standaloneSetup(myController);
        RestAssuredMockMvc.standaloneSetup(standaloneMockMvcBuilder);
        RestAssuredMockMvc.webAppContextSetup(webApplicationContext);
    }

}

myFirstScenario.groovy (пакет:"/ тест / ресурсы / контракты"):

import org.springframework.cloud.contract.spec.Contract

Contract.make {
    description "should return ok"
    request {
        method GET()
        url("/api/contract/test") {
            headers {
                header("Authorization","Bearer FOO")
            }
        }
    }
    response {
        status 200
    }
}

MyController.java:

@RestController
@RequestMapping(value = "/api/contract")
@PreAuthorize("hasRole('ROLE_ADMIN')")
public class MyController {
...
}

если вы хотите протестировать пользователей без прав администратора, вы можете использовать:

@WithMockUser(username = "admin", roles = {"USER"})
Другие вопросы по тегам