SUMMARY
Spring Data JPA Repository calls can only be authenticated in a integration test after a RestAssured call has been authenticated.
IMPACT
I can always use RestAssured given()
to perform the setup, but it's a lot quicker to do it with direct calls to the repository. However the current semantics are confusing. For example when authenticating first with RestAssured, then the SecurityContext, and again with RestAssured, the test will pass (Last example).
EXAMPLE
In order to use Spring Data JPA repositories in combination with Spring Security (The starter) inside integration tests while performing setup, I first need to authenticate using the SecurityContextHolder as shown below:
@Test
public void getValidContact() {
SecurityContextHolder.getContext()
.setAuthentication(new UsernamePasswordAuthenticationToken(ADMIN_USER,
PASSWORD,
Collections.singleton(new SimpleGrantedAuthority("ROLE_ADMIN"))));
Contact contact = CR.save(validContact);
given().auth()
.basic(ADMIN_USER, PASSWORD)
.get(contactRestPath + "{id}", contact.getId())
.then()
.statusCode(HttpStatus.OK.value())
.body("firstName", is(contact.getFirstName()))
.body("id", is(contact.getId().intValue()));
CR.deleteAll();
}
However this breaks RestAssured's ability to authenticate. The above test fails with an AccessDeniedException
. The below test will pass:
@Test
public void getInvalidValidContact2() {
given().auth()
.basic(ADMIN_USER, PASSWORD)
.get(contactRestPath + "{id}", 1L)
.then()
.statusCode(HttpStatus.INTERNAL_SERVER_ERROR.value());
}
This is only the case when authenticating with the SecurityContextHolder prior to authenticating with RestAssured. For example this test passes:
@Test
public void updateContact() {
Response response =
given().auth()
.basic(ADMIN_USER, PASSWORD)
.contentType("application/json")
.body(gson.toJson(validContact))
.when()
.post(contactRestPath);
String contactJson = response.getBody().asString();
Contact received = gson.fromJson(contactJson, Contact.class);
// The id is not null since it was saved to the database.
assertTrue(!Objects.isNull(received.getId()));
assertThat(received.getFirstName(), is(validContact.getFirstName()));
SecurityContextHolder.getContext()
.setAuthentication(new UsernamePasswordAuthenticationToken(ADMIN_USER,
PASSWORD,
Collections.singleton(new SimpleGrantedAuthority("ROLE_ADMIN"))));
assertThat(CR.findAll().size(), is(1));
received.setFirstName("Brooke");
given().auth()
.basic(ADMIN_USER, PASSWORD)
.contentType("application/json")
.body(gson.toJson(received))
.when()
.post(contactRestPath);
Contact update = CR.findOne(received.getId());
assertThat(update.getFirstName(), is(received.getFirstName()));
CR.deleteAll();
}