Skip to content

Commit 4d72aae

Browse files
towocrobinso
authored andcommitted
Client side certificate support
Adds the `cert` command line and configuration options that allow you to specify a client-side certificate file to use for TLS authentication against the web server. File format should be concatenated certificate and (unencrypted) private key. Encrypted private key should also be possible, but would have to deal with passing the password along to `requests`, and I'm not comfortable enough with Python to actually facilitate that.
1 parent 13783ac commit 4d72aae

3 files changed

Lines changed: 16 additions & 4 deletions

File tree

bugzilla/_cli.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,8 @@ def _setup_root_parser():
148148
'specified command.')
149149
p.add_argument('--username', help="Log in with this username")
150150
p.add_argument('--password', help="Log in with this password")
151+
p.add_argument('--cert', default=None, help="Log in with this "
152+
"certificate")
151153

152154
p.add_argument('--ensure-logged-in', action="store_true",
153155
help="Raise an error if we aren't logged in to bugzilla. "
@@ -1031,7 +1033,8 @@ def _make_bz_instance(opt):
10311033
url=opt.bugzilla,
10321034
cookiefile=cookiefile,
10331035
tokenfile=tokenfile,
1034-
sslverify=opt.sslverify)
1036+
sslverify=opt.sslverify,
1037+
cert=opt.cert)
10351038
return bz
10361039

10371040

bugzilla/base.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -260,14 +260,16 @@ def _listify(val):
260260

261261

262262
def __init__(self, url=-1, user=None, password=None, cookiefile=-1,
263-
sslverify=True, tokenfile=-1, use_creds=True, api_key=None):
263+
sslverify=True, tokenfile=-1, use_creds=True, api_key=None, cert=None):
264264
"""
265265
:param url: The bugzilla instance URL, which we will connect
266266
to immediately. Most users will want to specify this at
267267
__init__ time, but you can defer connecting by passing
268268
url=None and calling connect(URL) manually
269269
:param user: optional username to connect with
270270
:param password: optional password for the connecting user
271+
:param cert: optional certificate file for client side certificate
272+
authentication
271273
:param cookiefile: Location to cache the login session cookies so you
272274
don't have to keep specifying username/password. Bugzilla 5+ will
273275
use tokens instead of cookies.
@@ -294,6 +296,7 @@ def __init__(self, url=-1, user=None, password=None, cookiefile=-1,
294296
self.user = user or ''
295297
self.password = password or ''
296298
self.api_key = api_key
299+
self.cert = cert or ''
297300
self.url = ''
298301

299302
self._proxy = None
@@ -500,6 +503,9 @@ def readconfig(self, configpath=None):
500503
elif key == "password":
501504
log.debug("bugzillarc: setting password")
502505
self.password = val
506+
elif key == "cert":
507+
log.debug("bugzillarc: setting cert")
508+
self.cert = val
503509
else:
504510
log.debug("bugzillarc: unknown key=%s", key)
505511

@@ -533,7 +539,7 @@ def connect(self, url=None):
533539
url = self.fix_url(url)
534540

535541
self._transport = _RequestsTransport(
536-
url, self._cookiejar, sslverify=self._sslverify)
542+
url, self._cookiejar, sslverify=self._sslverify, cert=self.cert)
537543
self._transport.user_agent = self.user_agent
538544
self._proxy = _BugzillaServerProxy(url, self.tokenfile,
539545
self._transport)

bugzilla/transport.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ class _RequestsTransport(Transport):
109109
user_agent = 'Python/Bugzilla'
110110

111111
def __init__(self, url, cookiejar=None,
112-
sslverify=True, sslcafile=None, debug=0):
112+
sslverify=True, sslcafile=None, debug=True, cert=None):
113113
if hasattr(Transport, "__init__"):
114114
Transport.__init__(self, use_datetime=False)
115115

@@ -137,6 +137,8 @@ def __init__(self, url, cookiejar=None,
137137
# Using an explicit Session, rather than requests.get, will use
138138
# HTTP KeepAlive if the server supports it.
139139
self.session = requests.Session()
140+
if cert:
141+
self.session.cert = cert
140142

141143
def parse_response(self, response):
142144
""" Parse XMLRPC response """
@@ -167,6 +169,7 @@ def _request_helper(self, url, request_body):
167169
# Save is required only if we have a filename
168170
self._cookiejar.save()
169171

172+
log.debug(response.text)
170173
response.raise_for_status()
171174
return self.parse_response(response)
172175
except requests.RequestException as e:

0 commit comments

Comments
 (0)