Skip to content Skip to sidebar Skip to footer

Does Urllib2 Support Preemptive Authentication Authentication?

I am trying access a REST API. I can get it working in Curl/REST Client (the UI tool), with preemptive authentication enabled. But, using urllib2, it doesn't seem to support this b

Solution 1:

Here's a simple Preemptive HTTP basic auth handler, based on the code from urllib2.HTTPBasicAuthHandler. It can be used in the exact same manner, except an Authorization header will be added to every request with a matching URL. Note that this handler should be used with a HTTPPasswordMgrWithDefaultRealm. That's because there is no realm coming back in a WWW-Authenticate challenge since you're being preemptive.

classPreemptiveBasicAuthHandler(urllib2.BaseHandler):

        def__init__(self, password_mgr=None):
                if password_mgr isNone:
                        password_mgr = urllib2.HTTPPasswordMgrWithDefaultRealm()
                self.passwd = password_mgr
                self.add_password = self.passwd.add_password

        defhttp_request(self,req):
                uri = req.get_full_url()
                user, pw = self.passwd.find_user_password(None,uri)
                #logging.debug('ADDING REQUEST HEADER for uri (%s): %s:%s',uri,user,pw)if pw isNone: return req

                raw = "%s:%s" % (user, pw)
                auth = 'Basic %s' % base64.b64encode(raw).strip()
                req.add_unredirected_header('Authorization', auth)
                return req

Solution 2:

similar to @thom-nichols's answer; but subclassing HTTPBasicAuthHandler also handling HTTPS requests.

import urllib2
import base64

classPreemptiveBasicAuthHandler(urllib2.HTTPBasicAuthHandler):
    '''Preemptive basic auth.

    Instead of waiting for a 403 to then retry with the credentials,
    send the credentials if the url is handled by the password manager.
    Note: please use realm=None when calling add_password.'''defhttp_request(self, req):
        url = req.get_full_url()
        realm = None# this is very similar to the code from retry_http_basic_auth()# but returns a request object.
        user, pw = self.passwd.find_user_password(realm, url)
        if pw:
            raw = "%s:%s" % (user, pw)
            auth = 'Basic %s' % base64.b64encode(raw).strip()
            req.add_unredirected_header(self.auth_header, auth)
        return req

    https_request = http_request

here is an example for dealing with a jenkins server which does not send you 401 http errors (retry with auth). I'm using urllib2.install_opener to make things easy.

jenkins_url = "https://jenkins.example.com"
username = "johndoe"
api_token = "some-cryptic-value"

auth_handler = PreemptiveBasicAuthHandler()
auth_handler.add_password(
    realm=None, # default realm.
    uri=jenkins_url,
    user=username,
    passwd=api_token)
opener = urllib2.build_opener(auth_handler)
urllib2.install_opener(opener)

Solution 3:

Depending on what kind of authentication is required, you can send the Authorization headers manually by adding them to your request before you send out a body.

Post a Comment for "Does Urllib2 Support Preemptive Authentication Authentication?"