【问题标题】:Jenkins stapler requests fail with no valid crumb詹金斯订书机请求失败,没有有效的面包屑
【发布时间】:2023-11-13 18:46:01
【问题描述】:

我正在开发一个 Jenkins 插件,但现在我正试图使用​​ JavaScript 代理获取方法的返回值,如 here 所述。

我只是想调用这个 kotlin 方法:

@JavaScriptMethod
fun getMonitoredJobsAsJSON(): JSONArray = toJSON(getObjectMapper().writeValueAsString(getMonitoredJobs())) as JSONArray

从果冻脚本中使用:

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

  board.getMonitoredJobsAsJSON(function(data) {
   //
  })
</script>

当我在 Jenkins 服务器上禁用 CSRF 保护时,这实际上有效,但我显然不想这样做。开启 CSRF 保护后,我总是会收到 no valid crumb found 403 错误:

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

我知道如何从 crumbIssuer 端点检索 crumbs 以与 Jenkins rest api 交互,但我几乎没有找到任何资源来说明如何使其适用于插件中的订书机请求。

另外,当我检查请求时,请求中实际上设置了一个 crumb 标头:

提前感谢您的帮助。

【问题讨论】:

标签: jenkins jenkins-plugins csrf hudson hudson-plugins


【解决方案1】:

几周后,我终于找到了解决办法。

问题在于,由于某种原因,默认情况下附加到请求的 crumb 标头的名称实际上是错误的。它是Crumb,如我问题中的屏幕截图所示,但对于旧版本的Jenkins,它实际上应该是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
}

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

fun getRemoteRequestCrumb(): JSONObject = toJSON(
    SerializationUtils.getObjectWriter().writeValueAsString(RemoteRequestCrumb())
) as JSONObject

现在您可以像使用任何其他插件属性一样从 jelly 脚本请求 crumb 数据:${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;
  }
}

【讨论】:

    最近更新 更多