Question

this is probably a dumb question but I just cannot find a way how to create AuthHandler which would add Authorization header to the FIRST request. The only thing I see in urllib2.py are various http_error handler which add Authorization header to the ADDITIONAL request which handles the error.

However, when looking at http://www.ietf.org/rfc/rfc2617.txt, section 2, I see this:

A client MAY preemptively send the corresponding Authorization header with requests for resources in that space without receipt of another challenge from the server.

And really many servers (e.g., api.github.com) expect the Authorization header to be sent with the initial request, and actually they broke so instead of 401 they send 404 status code.

Anybody has any idea how to subclass *AuthHandler so that it would add the header on the initial request?

BTW, for many reasons unrelated to the question, no, python-requests is not the answer. Please, don't waste our time suggesting it. The answer has to be in context of stdlib only.

Was it helpful?

Solution

OK, so in the end it is http_request method. So, for example, this is the script to add a new bug to GitHub:

from base64 import standard_b64encode
import http.client
from urllib.request import (HTTPBasicAuthHandler, Request, HTTPSHandler,
                            build_opener, HTTPPasswordMgrWithDefaultRealm)
import json
import os
from configparser import ConfigParser
http.client.HTTPConnection.debuglevel = 1


class HTTPBasicPriorAuthHandler(HTTPBasicAuthHandler):
    handler_order = 400

    def http_request(self, req):
        if not req.has_header('Authorization'):
            user, passwd = self.passwd.find_user_password(None,
                                                          req.get_host())
            credentials = '{0}:{1}'.format(user, passwd).encode()
            auth_str = standard_b64encode(credentials).decode()
            req.add_unredirected_header('Authorization',
                                        'Basic {}'.format(auth_str.strip()))
        return req

    https_request = http_request

cp = ConfigParser()
cp.read(os.path.expanduser('~/.githubrc'))

# That configuration file should look something like
# [github]
# user=mylogin
# password=myveryverysecretpassword

gh_user = cp.get('github', 'user')
gh_passw = cp.get('github', 'password')
repo = 'reponame'

pwd_manager = HTTPPasswordMgrWithDefaultRealm()
pwd_manager.add_password(None, 'https://api.github.com', gh_user, gh_passw)
auth_prior_handler = HTTPBasicPriorAuthHandler(pwd_manager)
verbose_handler = HTTPSHandler(debuglevel=2)

opener = build_opener(verbose_handler, auth_prior_handler)

# Be careful that there is no slash in the end of the URL
gh_url = "https://api.github.com/repos/{0}/{1}/issues".format(gh_user, repo)

create_data = {
    'title': 'Testing bug summary',
    'body': '''This is a testing bug. I am writing here this stuff,
            just to have some text for body.''',
    'labels': ['somelabel']
}

gh_req = Request(gh_url, json.dumps(create_data).encode('utf8'))

handler = opener.open(gh_req)

print(handler.getcode())
print(handler)

Actually, now I believe the answer to this question is using my urllib2_prior_auth package.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top