How to test spring-security-oauth2 resource server security?

JavaSpring SecuritySpring Security-Oauth2

Java Problem Overview


Following the release of Spring Security 4 and it's improved support for testing I've wanted to update my current Spring security oauth2 resource server tests.

At present I have a helper class that sets up a OAuth2RestTemplate using ResourceOwnerPasswordResourceDetails with a test ClientId connecting to an actual AccessTokenUri to requests a valid token for my tests. This resttemplate is then used to make requests in my @WebIntegrationTests.

I'd like to drop the dependency on the actual AuthorizationServer, and the use of valid (if limited) user credentials in my tests, by taking advantage of the new testing support in Spring Security 4.

Up to now all my attempts at using @WithMockUser, @WithSecurityContext, SecurityMockMvcConfigurers.springSecurity() & SecurityMockMvcRequestPostProcessors.* have failed to make authenticated calls through MockMvc, and I can not find any such working examples in the Spring example projects.

Can anyone help me test my oauth2 resource server with some kind of mocked credentials, while still testing the security restrictions imposed?

** EDIT ** Sample code available here: https://github.com/timtebeek/resource-server-testing For each of the test classes I understand why it won't work as it, but I'm looking for ways that would allow me to test the security setup easily.

I'm now thinking of creating a very permissive OAuthServer under src/test/java, which might help a bit. Does anyone have any other suggestions?

Java Solutions


Solution 1 - Java

To test resource server security effectively, both with MockMvc and a RestTemplate it helps to configure an AuthorizationServer under 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());
	}
}

Integration test
For integration tests one can then simply use built in OAuth2 test support rule and annotions:

@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 test
Testing with MockMvc is also possible, but needs a little helper class to get a RequestPostProcessor that sets the Authorization: Bearer <token> header on requests:

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

Your MockMvc tests must then get a RequestPostProcessor from the OauthHelper class and pass it when making requests:

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

A full sample project is available on GitHub:
https://github.com/timtebeek/resource-server-testing

Solution 2 - Java

I found a much easier way to do this following directions I read here: http://docs.spring.io/spring-security/site/docs/4.0.x/reference/htmlsingle/#test-method-withsecuritycontext. This solution is specific to testing @PreAuthorize with #oauth2.hasScope but I'm sure it could be adapted for other situations as well.

I create an annotation which can be applied to @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;
    }
}

Example test using 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());
    }
}

And this is the controller under test:

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

Solution 3 - Java

Spring Boot 1.5 introduced test slices like @WebMvcTest. Using these test slices and manually load the OAuth2AutoConfiguration gives your tests less boilerplate and they'll run faster than the proposed @SpringBootTest based solutions. If you also import your production security configuration, you can test that the configured filter chains is working for your web services.

Here's the setup along with some additional classes that you'll probably find beneficial:

Controller:

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

Test:

@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 (this is for production):

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

}

Custom annotation for injecting scopes from tests:

@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";

}

Factory class for handling the custom annotation:

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;
    }
}

I use a copy of the response from our identity server for creating a realistic OAuth2Authentication. You can probably just copy my code. If you want to repeat the process for your identity server, place a breakpoint in org.springframework.security.oauth2.provider.token.RemoteTokenServices#loadAuthentication or org.springframework.boot.autoconfigure.security.oauth2.resource.UserInfoTokenServices#extractAuthentication, depending on whether you have configured a custom ResourceServerTokenServices or not.

Solution 4 - Java

There is alternative approach which I believe to be cleaner and more meaningful.

The approach is to autowire the token store and then add a test token which can then be used by the rest client.

An example test:

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

}

Personally I believe that it is not appropriate to unit test a controller with security enabled since security is a separate layer to the controller. I would create an integration test that tests all of the layers together. However the above approach can easily be modified to create a Unit Test with that uses MockMvc.

The above code is inspired by a Spring Security test written by Dave Syer.

Note this approach is for resource servers that share the same token store as the authorisation server. If your resource server does not share the same token store as the authorisation server I recommend using wiremock to mock the http responses.

Solution 5 - Java

I have another solution for this. See below:

@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
	private FilterChainProxy springSecurityFilterChain;
	
	@Autowired
	private UserRepository users;
	
	@Autowired
	private PasswordEncoder passwordEncoder;
	
	@Autowired
	private 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", "write")
					.autoApprove(true)
					.build();

    	 clientDetialsService.addClient(testClient);

    	 User user = createDefaultUser("testuser", passwordEncoder.encode("testpassword"), "max", "Mustermann", new Email("[email protected]"));

    	 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;
	}
}

Hope it will help!

Solution 6 - Java

OK, I've not yet been able to test my standalone oauth2 JWT token protected resource-server using the new @WithMockUser or related annotations.

As a workaround, I have been able to integration test my resource server security by setting up a permissive AuthorizationServer under src/test/java, and having that define two clients I use through a helper class. This gets me some of the way there, but it's not yet as easy as I'd like to test various users, roles, scopes, etc.

I'm guessing from here on it should be easier to implement my own WithSecurityContextFactory that creates an OAuth2Authentication, instead of the usual UsernamePasswordAuthentication. However, I have not yet been able to work out the detail of how to easily set this up. Any comments or suggestions how to set this up are welcome.

Solution 7 - Java

I found an easy and rapid way for testing spring security resource server with any token store. Im my example @EnabledResourceServeruses jwt token store.

The magic here is I replaced JwtTokenStore with InMemoryTokenStore at integration test.

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

}

Solution 8 - Java

One more solution I tried to detail enough :-D

It is based on setting an Authorization header, like some above, but I wanted:

  • Not to create actually valid JWT tokens and using all JWT authentication stack (unit tests...)
  • Test authentication to contain test-case defined scopes and authorities

So I've:

  • created custom annotations to set up a per-test OAuth2Authentication: @WithMockOAuth2Client (direct client connection) & @WithMockOAuth2User (client acting on behalf of an end user => includes both my custom @WithMockOAuth2Client and Spring @WithMockUser)
  • @MockBean the TokenStore to return the OAuth2Authentication configured with above custom annotations
  • provide MockHttpServletRequestBuilder factories that set a specific Authorization header intercepted by TokenStore mock to inject expected authentication.

The result to get you tested:

@WebMvcTest(MyController.class) // Controller to unit-test
@Import(WebSecurityConfig.class) // your class extending WebSecurityConfigurerAdapter
public class MyControllerTest extends OAuth2ControllerTest {

    @Test
    public void testWithUnauthenticatedClient() throws Exception {
        api.post(payload, "/endpoint")
                .andExpect(...);
    }

    @Test
    @WithMockOAuth2Client
    public void testWithDefaultClient() throws Exception {
        api.get("/endpoint")
                .andExpect(...);
    }

    @Test
    @WithMockOAuth2User
    public void testWithDefaultClientOnBehalfDefaultUser() throws Exception {
            MockHttpServletRequestBuilder req = api.postRequestBuilder(null, "/uaa/refresh")
                .header("refresh_token", JWT_REFRESH_TOKEN);

        api.perform(req)
                .andExpect(status().isOk())
                .andExpect(...)
    }

    @Test
    @WithMockOAuth2User(
        client = @WithMockOAuth2Client(
                clientId = "custom-client",
                scope = {"custom-scope", "other-scope"},
                authorities = {"custom-authority", "ROLE_CUSTOM_CLIENT"}),
        user = @WithMockUser(
                username = "custom-username",
                authorities = {"custom-user-authority"}))
    public void testWithCustomClientOnBehalfCustomUser() throws Exception {
        api.get(MediaType.APPLICATION_ATOM_XML, "/endpoint")
                .andExpect(status().isOk())
                .andExpect(xpath(...));
    }
}

Solution 9 - Java

I've tried many ways. But my solution is easier than others. I'm using OAuth2 JWT authentication in my spring boot application. My goal is to do a contract test. I'm writing a script with groovy and the contract plugin generates test codes for me. Therefore, I cannot interfere with the codes. I have a simple BaseTest class. I need to do all the necessary configurations in this class. This solution worked for me.

Imported dependency:

<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>

Imported Plugins:

    <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 (package:"/test/resources/contracts"):

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 {
...
}

if you want to test for non-admin users you can use:

@WithMockUser(username = "admin", roles = {"USER"})

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionTimView Question on Stackoverflow
Solution 1 - JavaTimView Answer on Stackoverflow
Solution 2 - JavamclaassenView Answer on Stackoverflow
Solution 3 - JavagogstadView Answer on Stackoverflow
Solution 4 - JavaThomas Turrell-CroftView Answer on Stackoverflow
Solution 5 - JavaRocks360View Answer on Stackoverflow
Solution 6 - JavaTimView Answer on Stackoverflow
Solution 7 - JavatalipkorkmazView Answer on Stackoverflow
Solution 8 - Javach4mpView Answer on Stackoverflow
Solution 9 - JavaBilal DemirView Answer on Stackoverflow