Skip to content

Commit c5708a4

Browse files
author
pjkersha
committed
Added http basic auth support
git-svn-id: http://proj.badc.rl.ac.uk/svn/ndg-security/trunk/ndg_httpsclient@8182 051b1e3e-aa0c-0410-b6c2-bfbade6052be
1 parent 1e8ae88 commit c5708a4

File tree

1 file changed

+49
-5
lines changed

1 file changed

+49
-5
lines changed

ndg/httpsclient/utils.py

Lines changed: 49 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@
1414
from optparse import OptionParser
1515
import os
1616
import urllib2
17-
from urllib2 import HTTPHandler, HTTPCookieProcessor
17+
from urllib2 import (HTTPHandler, HTTPCookieProcessor,
18+
HTTPBasicAuthHandler, HTTPPasswordMgrWithDefaultRealm)
1819

1920
import urlparse
2021

@@ -126,6 +127,8 @@ def open_url(url, config, data=None, handlers=None):
126127
@type config: Configuration
127128
@param data: HTTP POST data
128129
@type data: str
130+
@param handlers: list of custom urllib2 handlers to add to the request
131+
@type handlers: iterable
129132
@return: tuple (
130133
returned HTTP status code or 0 if an error occurred
131134
returned message or error description
@@ -154,6 +157,15 @@ def open_url(url, config, data=None, handlers=None):
154157
https_handler = HTTPSContextHandler(config.ssl_context,
155158
debuglevel=debuglevel)
156159
handlers.extend([http_handler, https_handler])
160+
161+
if config.http_basicauth:
162+
# currently only supports http basic auth
163+
auth_handler = HTTPBasicAuthHandler(HTTPPasswordMgrWithDefaultRealm())
164+
auth_handler.add_password(realm=None, uri=url,
165+
user=config.httpauth[0],
166+
passwd=config.httpauth[1])
167+
handlers.append(auth_handler)
168+
157169

158170
# Explicitly remove proxy handling if the host is one listed in the value of
159171
# the no_proxy environment variable because urllib2 does use proxy settings
@@ -167,13 +179,18 @@ def open_url(url, config, data=None, handlers=None):
167179
log.debug("Configuring proxies: %s" % config.proxies)
168180

169181
opener = build_opener(*handlers, ssl_context=config.ssl_context)
182+
183+
headers = config.headers
184+
if headers is None:
185+
headers = {}
186+
request = urllib2.Request(url, data, headers)
170187

171188
# Open the URL and check the response.
172189
return_code = 0
173190
return_message = ''
174191
response = None
175192
try:
176-
response = opener.open(url, data)
193+
response = opener.open(request)
177194
return_message = response.msg
178195
return_code = response.code
179196
if log.isEnabledFor(logging.DEBUG):
@@ -231,7 +248,7 @@ class Configuration(object):
231248
"""Connection configuration.
232249
"""
233250
def __init__(self, ssl_context, debug=False, proxies=None, no_proxy=None,
234-
cookie=None):
251+
cookie=None, http_basicauth=None, headers=None):
235252
"""
236253
@param ssl_context: SSL context to use with this configuration
237254
@type ssl_context: OpenSSL.SSL.Context
@@ -243,12 +260,18 @@ def __init__(self, ssl_context, debug=False, proxies=None, no_proxy=None,
243260
@type no_proxy: basestring
244261
@param cookie: cookies to set for request
245262
@type cookie: cookielib.CookieJar
263+
@param http_basicauth: http authentication, or None
264+
@type http_basicauth: tuple of (username,password)
265+
@param headers: http headers
266+
@type headers: dict
246267
"""
247268
self.ssl_context = ssl_context
248269
self.debug = debug
249270
self.proxies = proxies
250271
self.no_proxy = no_proxy
251272
self.cookie = cookie
273+
self.http_basicauth = http_basicauth
274+
self.headers = headers
252275

253276

254277
def main():
@@ -276,6 +299,12 @@ def main():
276299
parser.add_option("-n", "--no-verify-peer", action="store_true",
277300
dest="no_verify_peer", default=False,
278301
help="Skip verification of peer certificate.")
302+
parser.add_option("-a", "--basicauth", dest="auth", metavar="USER:PASSWD",
303+
default=None,
304+
help="HTTP authentication credentials")
305+
parser.add_option("--header", action="append", dest="headers",
306+
metavar="HEADER: VALUE",
307+
help="Add HTTP header to request")
279308
(options, args) = parser.parse_args()
280309
if len(args) != 1:
281310
parser.error("Incorrect number of arguments")
@@ -309,6 +338,17 @@ def main():
309338
else:
310339
data = None
311340

341+
if options.basicauth:
342+
http_basicauth = options.auth.split(':', 1)
343+
else:
344+
http_basicauth = None
345+
346+
headers = {}
347+
if options.headers:
348+
for h in options.headers:
349+
key, val = h.split(':', 1)
350+
headers[key.strip()] = val.lstrip()
351+
312352
# If a private key file is not specified, the key is assumed to be stored in
313353
# the certificate file.
314354
ssl_context = ssl_context_util.make_ssl_context(key_file,
@@ -318,9 +358,13 @@ def main():
318358
verify_peer,
319359
url)
320360

321-
config = Configuration(ssl_context, options.debug)
361+
config = Configuration(ssl_context,
362+
options.debug,
363+
http_basicauth=http_basicauth,
364+
headers=headers)
322365
if options.output_file:
323-
return_code, return_message = fetch_from_url_to_file(url,
366+
return_code, return_message = fetch_from_url_to_file(
367+
url,
324368
config,
325369
options.output_file,
326370
data)[:2]

0 commit comments

Comments
 (0)