Jenkins stapler requests fail with no valid crumb

两盒软妹~` 提交于 2021-02-07 14:42:05

问题


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

From the jelly script using this:

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

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

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)

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, a crumb header is actually set in the request:

Thanks in advance for any help.


回答1:


Weeks later, I finally found a solution to this.

The problem was that for some reason, the name of the crumb header appended to the requests by default is actually wrong. It's Crumb as shown in the screenshot in my question, but it actually should be Jenkins-Crumb or .crumb for older versions of Jenkins.

What I did was to find a way to retrieve a crumb and the correct header name from the server when the page is loading initially, and then append this crumb header using the correct name to any subsequent xhr requests.

I defined an entity for the crumbs:

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

And then add this entity to the plugin as an attribute:

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

Now you can request the crumb data from a jelly script as with any other plugin attribute: ${it.getRemoteRequestCrumb()}.

The last step is actually appending the correct header to all XHR requests:

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;
  }
}


来源:https://stackoverflow.com/questions/56983333/jenkins-stapler-requests-fail-with-no-valid-crumb

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!