Spring security 使用rest assured和basic auth与CSRF进行集成测试

Spring security 使用rest assured和basic auth与CSRF进行集成测试,spring-security,spring-boot,csrf,rest-assured,Spring Security,Spring Boot,Csrf,Rest Assured,我有一个基于AngularJs应用程序的工作Spring引导 我正在使用基本身份验证,我想为它编写一个集成测试。目前,我总是收到一个403状态代码,其中包含以下消息: Expected CSRF token not found. Has your session expired? 这是我的测试: @Test public void givenAdmin_deleteOfBookIsAllowed() { Response response = given().auth().preem

我有一个基于AngularJs应用程序的工作Spring引导

我正在使用基本身份验证,我想为它编写一个集成测试。目前,我总是收到一个403状态代码,其中包含以下消息:

Expected CSRF token not found. Has your session expired?
这是我的测试:

@Test
public void givenAdmin_deleteOfBookIsAllowed() {

    Response response = given().auth().preemptive().basic("admin", "admin").get("/api/user/");
    response.then().log().all();
    String sessionId = response.sessionId();
    String token = response.cookie("XSRF-TOKEN");

    Book book = Books.randomBook();
    bookRepository.save(book);

    given()
            .sessionId(sessionId)
            .cookie("XSRF-TOKEN", token)
            .header("X-XSRF-TOKEN", token)
            .pathParam("id", book.getId().getId())
            .when().delete("/api/books/{id}")
            .then().statusCode(HttpStatus.SC_NO_CONTENT);
}
根据教程,我正在使用自定义令牌回购:

 private CsrfTokenRepository csrfTokenRepository() {
    HttpSessionCsrfTokenRepository repository = new HttpSessionCsrfTokenRepository();
    repository.setHeaderName("X-XSRF-TOKEN");
    return repository;
}
这是第一次呼叫的请求/响应:

HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: 0
X-Frame-Options: DENY
Set-Cookie: JSESSIONID=7020E58A8D6DC2C883FD5D6BD086512A; Path=/; HttpOnly
Set-Cookie: XSRF-TOKEN=6c44ae09-73f9-4115-bbbf-b01773ec1b91; Path=/
X-Application-Context: application:staging:0
Content-Type: application/json;charset=UTF-8
Transfer-Encoding: chunked
Content-Encoding: gzip
Vary: Accept-Encoding
Date: Fri, 08 Jan 2016 07:43:21 GMT

{
    "details": {
        "remoteAddress": "127.0.0.1",
        "sessionId": "7020E58A8D6DC2C883FD5D6BD086512A"
    },
    "authorities": [
        {
            "authority": "ROLE_ADMIN"
        },
        {
            "authority": "ROLE_USER"
        }
    ],
    "authenticated": true,
    "principal": {
        "password": null,
        "username": "admin",
        "authorities": [
            {
                "authority": "ROLE_ADMIN"
            },
            {
                "authority": "ROLE_USER"
            }
        ],
        "accountNonExpired": true,
        "accountNonLocked": true,
        "credentialsNonExpired": true,
        "enabled": true
    },
    "credentials": null,
    "name": "admin"
}
从第二个电话:

Request method: DELETE
Request path:   http://localhost:64588/api/books/04ad6d12-9b59-4ade-9a8a-e45daccb1f61
Proxy:          <none>
Request params: <none>
Query params:   <none>
Form params:    <none>
Path params:    id=04ad6d12-9b59-4ade-9a8a-e45daccb1f61
Multiparts:     <none>
Headers:        X-XSRF-TOKEN=6c44ae09-73f9-4115-bbbf-b01773ec1b91
                Accept=*/*
Cookies:        JSESSIONID=7020E58A8D6DC2C883FD5D6BD086512A
                XSRF-TOKEN=6c44ae09-73f9-4115-bbbf-b01773ec1b91
Body:           <none>

HTTP/1.1 403 Forbidden
Server: Apache-Coyote/1.1
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: 0
X-Frame-Options: DENY
Content-Type: application/json;charset=UTF-8
Transfer-Encoding: chunked
Content-Encoding: gzip
Vary: Accept-Encoding
Date: Fri, 08 Jan 2016 07:44:21 GMT

{
    "timestamp": "2016-01-08T07:44:21.963+0000",
    "status": 403,
    "error": "Forbidden",
    "message": "Expected CSRF token not found. Has your session expired?",
    "path": "/api/books/04ad6d12-9b59-4ade-9a8a-e45daccb1f61"
}
请求方法:删除
请求路径:http://localhost:64588/api/books/04ad6d12-9b59-4ade-9a8a-e45daccb1f61
代理:
请求参数:
查询参数:
表格参数:
路径参数:id=04ad6d12-9b59-4ade-9a8a-e45daccb1f61
多部分:
标题:X-XSRF-TOKEN=6c44ae09-73f9-4115-bbbf-b01773ec1b91
接受=*/*
Cookies:JSESSIONID=7020E58A8D6DC2C883FD5D6BD086512A
XSRF-TOKEN=6c44ae09-73f9-4115-bbbf-b01773ec1b91
正文:
HTTP/1.1 403禁止
服务器:ApacheCoote/1.1
X-Content-Type-Options:nosniff
X-XSS-Protection:1;模式=块
缓存控制:无缓存,无存储,最大年龄=0,必须重新验证
Pragma:没有缓存
过期日期:0
X帧选项:拒绝
内容类型:application/json;字符集=UTF-8
传输编码:分块
内容编码:gzip
改变:接受编码
日期:2016年1月8日星期五07:44:21 GMT
{
“时间戳”:“2016-01-08T07:44:21.963+0000”,
“状态”:403,
“错误”:“禁止”,
“消息”:“未找到预期的CSRF令牌。您的会话是否已过期?”,
“路径”:“/api/books/04ad6d12-9b59-4ade-9a8a-e45daccb1f61”
}

要在rest客户端或集成测试中使用spring security
CSRF
保护,您需要在post之前执行2个
GET

  • 发出
    GET
    登录请求。这将返回
    JSESSIONID
    令牌和
    XSRF-token
    令牌。如果将返回的
    XSRF-TOKEN
    用于
    POST
    将失败,因为我们使用空/假
    JSESSIONID
    获取它
  • 使用上一个请求中的
    JSESSIONID
    ,从第二个
    Get
    获取有用的
    XSRF-TOKEN
  • 现在您可以使用
    XSRF-TOKEN
    进行
    POST
  • 使用基本身份验证和CSRF保护的rest-assured集成测试示例:

    //1) get sessionId
    Response response =
            given().auth().preemptive().basic(userName, userPassword).contentType(JSON).
            when().get(PREFIX_URL + "/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 + "/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("param",paramValue)).
            body(someData).
            contentType(JSON).
    when().
            post(PREFIX_URL + "/post_some_data").
    then().
        log().all().assertThat().statusCode(200);
    

    如果你想知道,你可以禁用CSRF,但我不想禁用它。那么,我的答案对你有用吗?