Merge lp:~pfalcon/linaro-android-frontend/csrf-support into lp:linaro-android-frontend

Proposed by Paul Sokolovsky
Status: Merged
Approved by: Milo Casagrande
Approved revision: 325
Merged at revision: 325
Proposed branch: lp:~pfalcon/linaro-android-frontend/csrf-support
Merge into: lp:linaro-android-frontend
Diff against target: 97 lines (+25/-8)
1 file modified
android_build/frontend/api.py (+25/-8)
To merge this branch: bzr merge lp:~pfalcon/linaro-android-frontend/csrf-support
Reviewer Review Type Date Requested Status
Milo Casagrande (community) Approve
Review via email: mp+172365@code.launchpad.net

Description of the change

Add support for working with API when CSRF protection is enabled in Jenkins. Based on previous work by Danilo on linaro-android-build-tools.

To post a comment you must log in.
Revision history for this message
Milo Casagrande (milo) wrote :

Paul,

thanks for quickly working on this!
It looks good to me.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'android_build/frontend/api.py'
2--- android_build/frontend/api.py 2013-04-03 15:32:25 +0000
3+++ android_build/frontend/api.py 2013-07-01 16:21:03 +0000
4@@ -3,6 +3,7 @@
5 import subprocess
6 import urllib2
7 import hashlib
8+import json
9 import logging
10
11 from django.conf import settings
12@@ -50,6 +51,14 @@
13 resp = urllib2.urlopen(req)
14 return resp.read()
15
16+def get_csrf_headers():
17+ try:
18+ crumb_data = _authJenkins('crumbIssuer/api/json')
19+ except urllib2.HTTPError:
20+ # Ignore errors in case CSRF protection is not enabled
21+ return {}
22+ data = json.loads(crumb_data)
23+ return {data['crumbRequestField']: data['crumb']}
24
25 def messageFromJenkinsErrorPage(page_text):
26 """Try to extract a reasonable error message from a Jenkins error page.
27@@ -114,9 +123,12 @@
28 return etree.tostring(doc_root)
29
30
31-def postConfig(url, configXml):
32+def postConfig(url, configXml, extra_headers=None):
33+ headers = {'Content-Type': 'text/xml'}
34+ if extra_headers:
35+ headers.update(extra_headers)
36 try:
37- _authJenkins(url, configXml, {'Content-Type': 'text/xml'})
38+ _authJenkins(url, configXml, headers)
39 return None
40 except urllib2.HTTPError, e:
41 return HttpResponse(
42@@ -154,8 +166,9 @@
43 def build_now(request):
44 job_name = request.POST['build'][1:].replace('/', '_', 1)
45 log.info("Scheduling build of job: %s", job_name)
46+ csrf_headers = get_csrf_headers()
47 try:
48- _authJenkins('job/' + job_name + '/buildWithParameters?delay=0sec', '')
49+ _authJenkins('job/' + job_name + '/buildWithParameters?delay=0sec', '', csrf_headers)
50 except urllib2.HTTPError, e:
51 log.exception("Exception scheduling build:")
52 return HttpResponse(
53@@ -167,7 +180,8 @@
54
55 @editor_required
56 def delete(request):
57- _authJenkins('job/' + job_name_from_request(request) + '/doDelete', {})
58+ csrf_headers = get_csrf_headers()
59+ _authJenkins('job/' + job_name_from_request(request) + '/doDelete', {}, csrf_headers)
60 return HttpResponse(status=200)
61
62
63@@ -177,7 +191,8 @@
64 new_text = request.POST['newText']
65 oldConfig = getJobConfig(job_name)
66 newConfig = replaceConfigDefault(oldConfig, new_text)
67- resp = postConfig('job/' + job_name + '/config.xml', newConfig)
68+ csrf_headers = get_csrf_headers()
69+ resp = postConfig('job/' + job_name + '/config.xml', newConfig, csrf_headers)
70 if resp:
71 return resp
72 return HttpResponse(status=200)
73@@ -200,11 +215,12 @@
74 if isinstance(xml_base, HttpResponse):
75 return xml_base
76 new_config = replaceConfigDefault(xml_base, request.POST['config'])
77- resp = postConfig('createItem?name=' + new_job_name, new_config)
78+ csrf_headers = get_csrf_headers()
79+ resp = postConfig('createItem?name=' + new_job_name, new_config, csrf_headers)
80 if resp:
81 return resp
82 if request.POST.get('buildNow', False):
83- _authJenkins('job/' + new_job_name + '/buildWithParameters?delay=0sec')
84+ _authJenkins('job/' + new_job_name + '/buildWithParameters?delay=0sec', '', csrf_headers)
85 return HttpResponse(
86 '~%s/%s' % (ownerName, buildName),
87 status=200)
88@@ -251,7 +267,8 @@
89 triggers[0][:] = [etree.XML(daily_trigger % (minute, hour))]
90 else:
91 triggers[0][:] = []
92- resp = postConfig('job/' + job_name + '/config.xml', etree.tostring(tree))
93+ csrf_headers = get_csrf_headers()
94+ resp = postConfig('job/' + job_name + '/config.xml', etree.tostring(tree), csrf_headers)
95 if resp:
96 return resp
97 return HttpResponse('foo')

Subscribers

People subscribed via source and target branches