spring-attic/spring-boot-issues

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

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.