Authenticating using SecurityContextHolder breaks Rest Assured Authentication
oleersoy opened this issue · 5 comments
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();
}Cross referenced:
https://jira.spring.io/browse/SEC-2976
Thank you for the detailed report! Unfortunately, I'm not that familiar with RestAssured so I do not see the problem. Can you create a complete example and provide me a link to it so I can better understand? Thanks!
@oleersoy As described in the README, "this repository is designed to allow Spring Boot users and team members to contribute self-contained projects reproducing issues logged against Spring Boot’s issue tracker". The problem itself should be tracked in Spring Security's JIRA or, if you believe the issue is specific to Spring Boot, in Spring Boot's GitHub issues.
@wilkinsona thanks for the heads up. @rwinch I have created a self contained project here:
https://github.com/oleersoy/spring-boot-security-report
Let's move the discussion to the JIRA you created since this is not a boot issue.