CSRF token and formAuth

1,764 views
Skip to first unread message

Sille Kamoen

unread,
Dec 19, 2015, 2:19:02 PM12/19/15
to REST assured
I'm implementing CSRF in my REST application built with Spring Boot. 

However, I can't seem to get REST-assured to do anything I want with these tokens. I'm not sure how rest-assured does the form authenication, but I assumed that the given().auth() did a login request first, before attempting the request to be tested. However, RA goes straight to the requested url and can't find a token in the response (which isn't there because there was no login!). 

What needs to happen in my applicaiton, is that a token must be obtained before doing the actual request that is being tested. The response to a successful login then contains the csrf token for the test. There are no html pages in my application except for a loginform for testing purposes, it's JSON only (which makes sense for a REST-application right?). 

Is there a way to solve this issue?

Johan Haleby

unread,
Dec 19, 2015, 2:21:40 PM12/19/15
to rest-a...@googlegroups.com
Hi, 

Have you had a look in the CSRF documentation? I've successfully used RA with Spring Boot (spring security).

Regards,
/Johan

--
You received this message because you are subscribed to the Google Groups "REST assured" group.
To unsubscribe from this group and stop receiving emails from it, send an email to rest-assured...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Sille Kamoen

unread,
Dec 20, 2015, 6:26:50 AM12/20/15
to REST assured
Hi Johan,
I certainly have read it, but I think my application works differently then the way supported by RA. I'm now trying to adjust my application a little to accomodate for that, but it's still not working.

I believe the main problem is sessions. A CSRF token is stored in the session, but RA doesn't create one. When trying to POST to a csrf protected endpoint, the response will be a default spring one, stating that there was no csrf token in the session. 

{
   
"timestamp": 1450610468234,
   
"status": 403,
   
"error": "Forbidden",
   
"message": "Expected CSRF token not found. Has your session expired?",
   
"path": "/teams"
}

I tried solving this by creating a session before the test:

protected void createSession() {
       
Response tokenResponse = given().log().all().filter(sessionFilter).
               
get("/token").
               
then().log().all().
                extract
().response();
        sessionFilter
.getSessionId();
   
}

But then it's not picked up (because RA just tries posting again, instead of authenticating first) and I get another standard Spring response, again without CSRF token

{
   
"timestamp": 1450610601703,
   
"status": 403,
   
"error": "Forbidden",
   
"message": "Invalid CSRF Token 'null' was found on the request parameter '_csrf' or header 'X-CSRF-TOKEN'.",
   
"path": "/teams"
}

I have no idea what RA is expecting for it to pick up the CSRF tokens. If it just keeps blindly posting  before doing authentication, that's never going to work right?

Op zaterdag 19 december 2015 20:21:40 UTC+1 schreef Johan Haleby:

Sille Kamoen

unread,
Dec 20, 2015, 8:32:28 AM12/20/15
to REST assured
I ended up implementing the login flow myself. It's not optimal, but I think it's the best thing I could do. For future reference, here's my code:

Login function: SessionData simply holds the sessionId and csrf token
protected SessionData login(String username, String password) {
       
//@formatter:off
       
Response getLoginResponse =
            given
().
                filter
(sessionFilter).
           
when().
               
get("/login").
           
then().
                extract
().response();
       
//@formatter:on


       
String token = getLoginResponse.header("X-CSRF-TOKEN");


       
//@formatter:off
        given
().log().all().
            filter
(sessionFilter).
            param
("username", username).
            param
("password", password).
            param
("_csrf", token).
       
when().
            post
("/login");


       
Response tokenResponse =
            given
().log().all().
                filter
(sessionFilter).
           
when().

               
get("/token").
           
then().log().all().
                extract
().response();


        sessionFilter
.getSessionId();

       
//@formatter:on


       
return new SessionData(tokenResponse.header("X-CSRF-TOKEN"), sessionFilter.getSessionId());
   
}

Now, when testing a function that makes a POST to for example /teams, which needs authentication and a csrf token, this is how to make the request:

        SessionData sessionData = login("captain", "password");
       
Response response =
            given
().
                    header
(sessionData.getCsrfHeader()).
                    filter
(sessionFilter).
           
when().
                content
(team1).contentType(ContentType.JSON).
                post
("/teams").
           
then().
                extract
().response();

        logout
();

Hope this helps, as this was the kind of behaviour I expected from RA in the first place

Op zondag 20 december 2015 12:26:50 UTC+1 schreef Sille Kamoen:

Johan Haleby

unread,
Dec 20, 2015, 1:33:28 PM12/20/15
to rest-a...@googlegroups.com
Thanks a lot for sharing your code. REST Assured only support csrf tokens sent as a part of the login page and not in headers. But thanks to your code I think it'll be easier for me to implement support for "headers" as well.

Johan Haleby

unread,
Dec 20, 2015, 1:36:41 PM12/20/15
to rest-a...@googlegroups.com
Could you help out and create a small Spring sample application as well that uses mimics what your doing? That would probably help A LOT as well. I created the CSRF support to solve the use case I had when working with Spring (+Security) and that worked fine for me but it can (and should) obviously be improved. 

Sille Kamoen

unread,
Dec 20, 2015, 2:33:23 PM12/20/15
to rest-a...@googlegroups.com
Hi Johan,
I get that my case might be a little non-trivial, but I still don't quite understand how RA is currently supposed to work with CSRF. It seems to me it actually requires a form on every page you want to test, which sounds a bit weird to me for a REST application. I don't have that much experience with REST, so it's probably just me.

Anyway, I created a demo application at https://github.com/skamoen/rest-assured-csrf-demo. I hope it gets the point across, just let me know if you have any questions, I'd be happy to help. 

Op zo 20 dec. 2015 om 19:36 schreef Johan Haleby <johan....@gmail.com>:
You received this message because you are subscribed to a topic in the Google Groups "REST assured" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/rest-assured/HidZCdNA4iA/unsubscribe.
To unsubscribe from this group and all its topics, send an email to rest-assured...@googlegroups.com.
Reply all
Reply to author
Forward
0 new messages