Jenkins stapler requests fail with no valid crumb

con*_*.16 5 hudson csrf hudson-plugins jenkins jenkins-plugins

I'm working on a Jenkins plugin and I'm now stuck at a point where I'm trying to get the return value of a method using a JavaScript proxy as described here.

I simply want to call this kotlin method:

@JavaScriptMethod
fun getMonitoredJobsAsJSON(): JSONArray = toJSON(getObjectMapper().writeValueAsString(getMonitoredJobs())) as JSONArray
Run Code Online (Sandbox Code Playgroud)

From the jelly script using this:

<script>
  var board = <st:bind value="${it}"/>

  board.getMonitoredJobsAsJSON(function(data) {
   //
  })
</script>
Run Code Online (Sandbox Code Playgroud)

This actually works when I disable CSRF protection on the Jenkins server but I obviously don't want to do that. With CSRF protection on I always get a no valid crumb found 403 error:

POST http://localhost:8080/$stapler/bound/36dc05fc-c12d-4182-a008-60bcf5c49307/getMonitoredJobsAsJSON 403 (No valid crumb was included in the request)
Run Code Online (Sandbox Code Playgroud)

I know how to retrieve crumbs from the crumbIssuer end point for interacting with the Jenkins rest api but I've found virtually no resources on how to make it work for stapler requests in plugins.

Also, when I inspect the requests, there actually is a crumb header set in the request: 在此处输入图片说明

Thanks in advance for any help.

con*_*.16 1

几周后,我终于找到了解决方案。

问题是,由于某种原因,默认附加到请求的碎屑标头的名称实际上是错误的。Crumb正如我的问题中的屏幕截图所示,但它实际上应该是或Jenkins-Crumb对于.crumb旧版本的詹金斯。

我所做的就是找到一种方法,在页面最初加载时从服务器检索 crumb和正确的标头名称,然后使用正确的名称将此 crumb 标头附加到任何后续的 xhr 请求中。

我为面包屑定义了一个实体:

class RemoteRequestCrumb {
    @JsonIgnore private val crumbIssuer: CrumbIssuer? = Jenkins.getInstance()?.getCrumbIssuer()
    val fieldName: String? = crumbIssuer?.crumbRequestField
    val crumbValue: String? = crumbIssuer?.crumb
}
Run Code Online (Sandbox Code Playgroud)

然后将此实体作为属性添加到插件中:

fun getRemoteRequestCrumb(): JSONObject = toJSON(
    SerializationUtils.getObjectWriter().writeValueAsString(RemoteRequestCrumb())
) as JSONObject
Run Code Online (Sandbox Code Playgroud)

现在,您可以像使用任何其他插件属性一样从 jelly 脚本请求面包屑数据:${it.getRemoteRequestCrumb()}

最后一步实际上是将正确的标头附加到所有 XHR 请求中:

appendCrumbHeaderToAllRequests: function () {
  let crumb = JSON.parse(this.remoteRequestCrumb);
  let open = XMLHttpRequest.prototype.open;

  XMLHttpRequest.prototype.open = function() {
    let mutatedPrototype = open.apply(this, arguments);
    this.setRequestHeader(crumb.fieldName, crumb.crumbValue);
    return mutatedPrototype;
  }
}
Run Code Online (Sandbox Code Playgroud)