| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121 | """NTLM authenticating pool, contributed by erikcederstranIssue #10, see: http://code.google.com/p/urllib3/issues/detail?id=10"""from __future__ import absolute_importfrom logging import getLoggerfrom ntlm import ntlmfrom .. import HTTPSConnectionPoolfrom ..packages.six.moves.http_client import HTTPSConnectionlog = getLogger(__name__)class NTLMConnectionPool(HTTPSConnectionPool):    """    Implements an NTLM authentication version of an urllib3 connection pool    """    scheme = "https"    def __init__(self, user, pw, authurl, *args, **kwargs):        """        authurl is a random URL on the server that is protected by NTLM.        user is the Windows user, probably in the DOMAIN\\username format.        pw is the password for the user.        """        super(NTLMConnectionPool, self).__init__(*args, **kwargs)        self.authurl = authurl        self.rawuser = user        user_parts = user.split("\\", 1)        self.domain = user_parts[0].upper()        self.user = user_parts[1]        self.pw = pw    def _new_conn(self):        # Performs the NTLM handshake that secures the connection. The socket        # must be kept open while requests are performed.        self.num_connections += 1        log.debug(            "Starting NTLM HTTPS connection no. %d: https://%s%s",            self.num_connections,            self.host,            self.authurl,        )        headers = {"Connection": "Keep-Alive"}        req_header = "Authorization"        resp_header = "www-authenticate"        conn = HTTPSConnection(host=self.host, port=self.port)        # Send negotiation message        headers[req_header] = "NTLM %s" % ntlm.create_NTLM_NEGOTIATE_MESSAGE(            self.rawuser        )        log.debug("Request headers: %s", headers)        conn.request("GET", self.authurl, None, headers)        res = conn.getresponse()        reshdr = dict(res.getheaders())        log.debug("Response status: %s %s", res.status, res.reason)        log.debug("Response headers: %s", reshdr)        log.debug("Response data: %s [...]", res.read(100))        # Remove the reference to the socket, so that it can not be closed by        # the response object (we want to keep the socket open)        res.fp = None        # Server should respond with a challenge message        auth_header_values = reshdr[resp_header].split(", ")        auth_header_value = None        for s in auth_header_values:            if s[:5] == "NTLM ":                auth_header_value = s[5:]        if auth_header_value is None:            raise Exception(                "Unexpected %s response header: %s" % (resp_header, reshdr[resp_header])            )        # Send authentication message        ServerChallenge, NegotiateFlags = ntlm.parse_NTLM_CHALLENGE_MESSAGE(            auth_header_value        )        auth_msg = ntlm.create_NTLM_AUTHENTICATE_MESSAGE(            ServerChallenge, self.user, self.domain, self.pw, NegotiateFlags        )        headers[req_header] = "NTLM %s" % auth_msg        log.debug("Request headers: %s", headers)        conn.request("GET", self.authurl, None, headers)        res = conn.getresponse()        log.debug("Response status: %s %s", res.status, res.reason)        log.debug("Response headers: %s", dict(res.getheaders()))        log.debug("Response data: %s [...]", res.read()[:100])        if res.status != 200:            if res.status == 401:                raise Exception("Server rejected request: wrong username or password")            raise Exception("Wrong server response: %s %s" % (res.status, res.reason))        res.fp = None        log.debug("Connection established")        return conn    def urlopen(        self,        method,        url,        body=None,        headers=None,        retries=3,        redirect=True,        assert_same_host=True,    ):        if headers is None:            headers = {}        headers["Connection"] = "Keep-Alive"        return super(NTLMConnectionPool, self).urlopen(            method, url, body, headers, retries, redirect, assert_same_host        )
 |