Reputation: 73
I'm trying to write a web integration test with restassured spring security authentication. The application uses AngularJS and Spring Boot. Since I use AngularJS the CSRF protection is done with X-XSRF-TOKEN header and XSRF-TOKEN cookie (as I understand its default for angular).
How can I configure restassured to generated and send this token with form authentication ? Right now I have something like this:
given().auth().form("user", "password", new FormAuthConfig("login", "username", "password").sendCsrfTokenAsHeader()).when().get("/index.html").then().log().all().statusCode(200);
But in the logs I see that CSRF token is invalid when posting credentials to /login .
Upvotes: 4
Views: 6242
Reputation: 101
Use a RestAssured filter to retrieve and inject the token when needed.
Given the server's response to GET /login
always includes the token cookie. Then a solution which keeps the actual test code clean could look like this:
package com.example;
import static org.junit.jupiter.api.TestInstance.Lifecycle.PER_CLASS;
import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.DEFINED_PORT;
import org.junit.jupiter.api.*;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import io.restassured.RestAssured;
import io.restassured.authentication.FormAuthConfig;
import io.restassured.filter.*;
import io.restassured.response.Response;
import io.restassured.specification.*;
@ExtendWith(SpringExtension.class)
@TestInstance(PER_CLASS)
@SpringBootTest(webEnvironment = DEFINED_PORT)
public class CsrfSampleTest {
@BeforeAll
public void addCsrfCookieFilter() {
RestAssured.filters(new Filter() {
@Override
public Response filter(FilterableRequestSpecification requestSpec,
FilterableResponseSpecification responseSpec, FilterContext ctx) {
String csrfToken = requestSpec.getCookies().getValue("XSRF-TOKEN");
if (csrfToken == null) {
csrfToken = RestAssured.given().noFilters().get("/login").cookie("XSRF-TOKEN");
}
requestSpec.replaceHeader("X-XSRF-TOKEN", csrfToken);
return ctx.next(requestSpec, responseSpec);
}
});
}
@Test
public void test() {
RestAssured.given()
.auth().form("user", "password", new FormAuthConfig("login", "username", "password"))
.when()
.get("/index.html")
.then()
.statusCode(200);
}
}
Upvotes: 0
Reputation: 728
You need to do 2 GET
before post to use spring security CSRF protection in your rest client and test class.
GET
request to login. This will return the JSESSIONID
token and XSRF-TOKEN
tokens. If you use the returned XSRF-TOKEN
to POST
it will fail, because we got it using empty/false JSESSIONID
.XSRF-TOKEN
from the second GET
, using JSESSIONID
from previous request.XSRF-TOKEN
for your POST
.Example how to use CSRF protection with X-XSRF-TOKEN
in rest assured:
//1) get sessionId
Response response =
given().auth().preemptive().basic(userName, userPassword).contentType(JSON).
when().get(PREFIX_URL + "/users/user").
then().log().all().extract().response();
String jsessionidId = response.getSessionId();//or response.cookie("JSESSIONID");
//2) get XSRF-TOKEN using new/real sessionId
response =
given().
sessionId(jsessionidId).//or cookie("JSESSIONID", jsessionidId).
contentType(JSON).
when().get(PREFIX_URL + "/users/user").
then().log().all().extract().response();
//3) post data using XSRF-TOKEN
given().log().all().
sessionId(jsessionidId).//or cookie("JSESSIONID", jsessionidId).
header("X-XSRF-TOKEN", response.cookie("XSRF-TOKEN")).
queryParam("pos",pos.getId()).
queryParam("date",date).
queryParam("group_id",itemGroup.getId()).
body(orderItems).
contentType(JSON).
when().
post(PREFIX_URL + "/orders/orderitems").
then().
log().all().assertThat().statusCode(200);
Upvotes: 3
Reputation: 3791
Some delay in response but I hope it helps someone
Response loginResponse = given().contentType(APPLICATION_JSON).
param(USERNAME, "").
param(PASSWORD, "").
when().post(LOGIN_PROCESSING_URL).then().log().all().
extract().response();
given().contentType(APPLICATION_JSON).
cookie("XSRF-TOKEN", loginResponse.cookie("XSRF-TOKEN")).
header("X-XSRF-TOKEN", loginResponse.cookie("XSRF-TOKEN")).
sessionId(loginResponse.getSessionId()).
when().post(USER_PATH).
then().log().all().statusCode(CREATED.value());
Upvotes: 1