gpt4 book ai didi

java - 让 RestAssured 测试与 Spring Security CSRF for AngularJS 一起使用

转载 作者:行者123 更新时间:2023-12-01 09:53:14 26 4
gpt4 key购买 nike

我发现“The Login Page: Angular JS and Spring Security ”有很大帮助,可以将 CSRF 保护添加到使用 Spring(安全等)实现 AngularJS 应用程序使用的 REST API 的 Web 应用程序中。 AngularJS 应用程序使用基于表单的登录 (JSESSIONID) 进行身份验证。这是这项工作的本质:

  • 登录页面上的隐藏输入字段_csrf
  • CsrfHeaderFilterXSRF-TOKEN cookie 添加到响应
  • HttpSessionCsrfTokenRepositorysetHeaderName("X-XSRF-TOKEN")

一切都工作正常(据我观察)。

我相信这会导致以下流程:

  1. 重定向至登录页面
  2. 登录页面包含_csrf
  3. 登录响应包含 XSRF-TOKEN cookie
  4. Angular 在 REST 请求中使用 cookie 值作为 X-XSRF-TOKEN header
  5. 幸福!

第二个。似乎是普通的 Spring Security CSRF。 3.和4.似乎an attempt适应AngularJS CSRF support .

同样,通过测试临时实例,这一切都工作正常。然而,一些集成测试被破坏,特别是使用 RestAssured 的测试。我还没有找到有关 RestAssured 的良好示例。 This这是我能找到的所有文档。

它建议使用 formAuthConfig().withAutoDetectionOfCsrf()withCsrfFieldName("_csrf"),并对登录进行显式 get页。使用这个似乎可以很好地处理登录问题。但我不明白如何告诉 RestAssured 转向使用 X-XSRF-TOKEN header 。

我没有成功地尝试过这段代码的很多变体,但我目前有这个:

    FormAuthConfig baseConfig = new FormAuthConfig(loginPage, "username", "password");
FormAuthConfig config = baseConfig.sendCsrfTokenAsHeader();
config = config.withCsrfFieldName("X-XSRF-TOKEN");
RestAssured.authentication = RestAssured.form(userName, password, config);

given().auth().form("admin", "admin", baseConfig.withCsrfFieldName("_csrf"))
.when().get(loginPage)
.then().statusCode(200);

expect().statusCode(200)
.when().get(...); // line 246

这将获得以下输出:

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<title>Error 401 Unauthorized</title>
</head>
<body>
<h2>HTTP ERROR 401</h2>
<p>Problem accessing /application_name/rest/something. Reason:
</p>
<pre> Unauthorized</pre>
<hr/>
<i>
<small>Powered by Jetty://</small>
</i>
<hr/>
</body>
</html>

java.lang.IllegalArgumentException: Couldn't find the CSRF input field with name X-XSRF-TOKEN in response. Response was:
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<title>Error 401 Unauthorized</title>
</head>
<body>
<h2>HTTP ERROR 401</h2>
<p>Problem accessing /application_name/rest/something. Reason:
</p>
<pre> Unauthorized</pre>
<hr/>
<i>
<small>Powered by Jetty://</small>
</i>
<hr/>
</body>
</html>

at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:422)
at org.codehaus.groovy.reflection.CachedConstructor.invoke(CachedConstructor.java:80)
at org.codehaus.groovy.reflection.CachedConstructor.doConstructorInvoke(CachedConstructor.java:74)
at org.codehaus.groovy.runtime.callsite.ConstructorSite$ConstructorSiteNoUnwrap.callConstructor(ConstructorSite.java:84)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCallConstructor(CallSiteArray.java:60)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callConstructor(AbstractCallSite.java:235)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callConstructor(AbstractCallSite.java:247)
at com.jayway.restassured.internal.filter.FormAuthFilter.filter(FormAuthFilter.groovy:85)
at com.jayway.restassured.filter.Filter$filter.call(Unknown Source)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:48)
at com.jayway.restassured.filter.Filter$filter.call(Unknown Source)
at com.jayway.restassured.internal.filter.FilterContextImpl.next(FilterContextImpl.groovy:49)
at com.jayway.restassured.filter.FilterContext$next.call(Unknown Source)
at com.jayway.restassured.internal.RequestSpecificationImpl.invokeFilterChain(RequestSpecificationImpl.groovy:994)
<snip>
at com.jayway.restassured.internal.ResponseSpecificationImpl.get(ResponseSpecificationImpl.groovy)
at com.company.application_name.AbstractJettyJsonRestTest.getCollection(AbstractJettyJsonRestTest.java:246)
at com.company.application_name.JsonRestIntegrationTest.testSomething(JsonRestIntegrationTest.java:74)
<snip>
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:74)

非常感谢您的帮助!

最佳答案

如果您遵循 Google 论坛上概述的模式,则可以使用 RestAssured 进行 csrf 测试。 https://groups.google.com/forum/#!topic/rest-assured/HidZCdNA4iA

本质上,您必须创建一个辅助方法来手动启动登录流程,而不是依赖 RestAssured 来为您完成。以下是从原始位置复制以将其保留在 SO 上所需的代码。

protected SessionData login(String username, String password) {
Response getLoginResponse =
given().
filter(sessionFilter).
when().
get("/login.html").
then().
extract().response();

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

RestAssured.given().log().all().
filter(sessionFilter)
.header("X-XSRF-TOKEN", csrfToken)
.param("username", username)
.param("password", password)
.when()
.post("/login");


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

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

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

登录方法本质上是导航到登录页面,获取 csrf token ,使用该 token 登录,然后进行另一个调用以获取更新的 sessionId 和 csrf token ,因为它们在登录后发生变化。

Url 和 csrf 参数可能需要根据您的具体设置进行更改。

SessionData 只是一个自定义帮助器 POJO,用于存储数据

private class SessionData {
private String csrf;
private String session;
}

然后将其用于这样的测试

@Test
public void whenAdminAccessDiscoveryResource_thenSuccess() {
SessionData sessionData = login("admin", "admin");
final Response response = RestAssured.given()
.header("X-XSRF-TOKEN", sessionData.getCsrf())
.filter(sessionFilter)
.get(ROOT_URI + "/discovery");
Assert.assertEquals(HttpStatus.OK.value(), response.getStatusCode());
}

RestAssured 假定您的 sessionId 位于标记为“JSESSIONID”的 cookie 中。如果您的 sessionId 有不同的标签,您可以通过配置 RestAssured 查找该标签来更改此设置。

    RestAssured.config = config()
.sessionConfig(new SessionConfig().sessionIdName("SESSION"));

将“SESSION”替换为您的 sessionId 标签。

关于java - 让 RestAssured 测试与 Spring Security CSRF for AngularJS 一起使用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37456365/

26 4 0
文章推荐: java - 更新 List 中的对象仅影响特定字段。 (合并)