如何申请詹金斯的面包屑发行人

时间:2013-05-24 15:22:39

标签: api security jenkins

我想使用Jenkins Remote API,我正在寻找安全的解决方案。我遇到了Prevent Cross Site Request Forgery exploits,我想使用它,但是我在某个地方读到你必须提出碎屑请求。

如何获取crumb请求以使API正常工作?

我发现了这个https://github.com/entagen/jenkins-build-per-branch/pull/20,但我仍然不知道如何修复它。

我的Jenkins版本是1.50.x。

Authenticated remote API request responds with 403 when using POST request

8 个答案:

答案 0 :(得分:30)

我也没有在文档中找到这个。此代码针对较旧的Jenkins(1.466)进行了测试,但仍应有效。

要发出碎屑,请使用crumbIssuer

// left out: you need to authenticate with user & password -> sample below
HttpGet httpGet = new HttpGet(jenkinsUrl + "crumbIssuer/api/json");
String crumbResponse = toString(httpclient, httpGet);
CrumbJson crumbJson = new Gson().fromJson(crumbResponse, CrumbJson.class);

这会得到像这样的回复

{"crumb":"fb171d526b9cc9e25afe80b356e12cb7","crumbRequestField":".crumb"}

这包含您需要的两条信息

  1. 您需要传递碎屑的字段名称
  2. 面包屑本身
  3. 如果您现在想要从Jenkins获取内容,请将crumb添加为标题。在下面的示例中,我获取了最新的构建结果。

    HttpPost httpost = new HttpPost(jenkinsUrl + "rssLatest");
    httpost.addHeader(crumbJson.crumbRequestField, crumbJson.crumb);
    

    以下是整个示例代码。我正在使用gson 2.2.4来解析响应,并使用Apache's httpclient 4.2.3来完成剩下的工作。

    import org.apache.http.auth.*;
    import org.apache.http.client.*;
    import org.apache.http.client.methods.*;
    import org.apache.http.impl.client.*;
    
    import com.google.gson.Gson;
    
    public class JenkinsMonitor {
    
        public static void main(String[] args) throws Exception {
    
            String protocol = "http";
            String host = "your-jenkins-host.com";
            int port = 8080;
            String usernName = "username";
            String password = "passwort";
    
            DefaultHttpClient httpclient = new DefaultHttpClient();
            httpclient.getCredentialsProvider().setCredentials(
                    new AuthScope(host, port), 
                    new UsernamePasswordCredentials(usernName, password));
    
            String jenkinsUrl = protocol + "://" + host + ":" + port + "/jenkins/";
    
            try {
                // get the crumb from Jenkins
                // do this only once per HTTP session
                // keep the crumb for every coming request
                System.out.println("... issue crumb");
                HttpGet httpGet = new HttpGet(jenkinsUrl + "crumbIssuer/api/json");
                String crumbResponse= toString(httpclient, httpGet);
                CrumbJson crumbJson = new Gson()
                    .fromJson(crumbResponse, CrumbJson.class);
    
                // add the issued crumb to each request header
                // the header field name is also contained in the json response
                System.out.println("... issue rss of latest builds");
                HttpPost httpost = new HttpPost(jenkinsUrl + "rssLatest");
                httpost.addHeader(crumbJson.crumbRequestField, crumbJson.crumb);
                toString(httpclient, httpost);
    
            } finally {
                httpclient.getConnectionManager().shutdown();
            }
    
        }
    
        // helper construct to deserialize crumb json into 
        public static class CrumbJson {
            public String crumb;
            public String crumbRequestField;
        }
    
        private static String toString(DefaultHttpClient client, 
            HttpRequestBase request) throws Exception {
            ResponseHandler<String> responseHandler = new BasicResponseHandler();
            String responseBody = client.execute(request, responseHandler);
            System.out.println(responseBody + "\n");
            return responseBody;
        }
    
    }
    

答案 1 :(得分:4)

或者您可以使用Python和requests代替

req = requests.get('http://JENKINS_URL/crumbIssuer/api/xml?xpath=concat(//crumbRequestField,":",//crumb)', auth=(username, password))
print(req.text)

会给你起名字和面包屑:

Jenkins-Crumb:e2e41f670dc128f378b2a010b4fcb493

答案 2 :(得分:3)

User cheffe's answer帮助了90%。谢谢你给我们正确的方向。

缺少的10%围绕HTTP用户名和密码身份验证。

由于我使用的Codenameone Java API没有Authentication Class,

new UsernamePasswordCredentials(usernName, password));

我用过:

String apiKey = "yourJenkinsUsername:yourJenkinsPassword";
httpConnection.addRequestHeader("Authorization", "Basic " + Base64.encode(apiKey.getBytes()));

答案 3 :(得分:3)

此Python函数获取面包屑,并另外使用面包屑将其发布到Jenkins端点。在启用CSRF protection的Jenkins 2.46.3上对此进行了测试:

import urllib.parse
import requests

def build_jenkins_job(url, username, password):
    """Post to the specified Jenkins URL.

    `username` is a valid user, and `password` is the user's password or
    (preferably) hex API token.
    """
    # Build the Jenkins crumb issuer URL
    parsed_url = urllib.parse.urlparse(url)
    crumb_issuer_url = urllib.parse.urlunparse((parsed_url.scheme,
                                                parsed_url.netloc,
                                                'crumbIssuer/api/json',
                                                '', '', ''))

    # Get the Jenkins crumb
    auth = requests.auth.HTTPBasicAuth(username, password)
    r = requests.get(crumb_issuer_url, auth=auth)
    json = r.json()
    crumb = {json['crumbRequestField']: json['crumb']}

    # POST to the specified URL
    headers = {'Content-Type': 'application/x-www-form-urlencoded'}
    headers.update(crumb)
    r = requests.post(url, headers=headers, auth=auth)

username = 'jenkins'
password = '3905697dd052ad99661d9e9f01d4c045'
url = 'http://jenkins.example.com/job/sample/build'
build_jenkins_job(url, username, password)

答案 4 :(得分:2)

enter image description here

引荐-https://support.cloudbees.com/hc/en-us/articles/219257077-CSRF-Protection-Explained

如果您使用用户名和用户API令牌进行身份验证,则不需要Jenkins 2.96 weekly / 2.107 LTS的面包屑。有关更多信息,请参阅使用API​​令牌或JENKINS-22474进行身份验证时不再需要的CSRF屑。

答案 5 :(得分:1)

User cheffe's Java snippet在Jenkins v2.89.3(Eclipse.org)和我使用的另一个Jenkins实例上工作得很好,在v2.60.3(一旦启用 1 )。

我已将此添加到Maven mojo 2 我用于将本地编辑的config.xml更改推送回服务器。

1 CSRF Protection
2 Hudson job sync plugin

答案 6 :(得分:1)

同时,您可以生成API令牌,以防止必须在上述解决方案提供的源代码中包含密码:

https://wiki.jenkins.io/display/JENKINS/Authenticating+scripted+clients

答案 7 :(得分:0)

在所有这些答案中,我都没有找到使用HK SK YYYY-MM-DD-HH :MM:SS.00000 YYYY-MM-DD HH:MM:SS.00000 YYYY-MM DD-HH:MM:SS.0000 的选项。 我确实尝试了所有这些选项,但是如果要启用Jenkins API token保护,则应该使用CSRF而不是普通的Jenkins API token访问Jenkins API。 每个用户可以在用户配置页面中生成此令牌。 令牌可以如下使用-

password

P.S。 -此初始化适用于Ruby Jenkins API client

enter image description here