~stub/ubuntu/lucid/python-urllib3/devel

« back to all changes in this revision

Viewing changes to urllib3/contrib/ntlmpool.py

  • Committer: Package Import Robot
  • Author(s): Barry Warsaw
  • Date: 2012-11-01 15:31:36 UTC
  • mfrom: (1.1.2)
  • Revision ID: package-import@ubuntu.com-20121101153136-w2fm02askveqxxkx
Tags: 1.5-0ubuntu1
* New upstream release.  Remaining changes:
  - 01_do-not-use-embedded-python-six.patch: refreshed
  - 02_require-cert-verification.patch: refreshed
  - 03-fix-appenginge.patch: removed

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# urllib3/contrib/ntlmpool.py
2
 
# Copyright 2008-2012 Andrey Petrov and contributors (see CONTRIBUTORS.txt)
3
 
#
4
 
# This module is part of urllib3 and is released under
5
 
# the MIT License: http://www.opensource.org/licenses/mit-license.php
6
 
 
7
 
"""
8
 
NTLM authenticating pool, contributed by erikcederstran
9
 
 
10
 
Issue #10, see: http://code.google.com/p/urllib3/issues/detail?id=10
11
 
"""
12
 
 
13
 
try:
14
 
    from http.client import HTTPSConnection
15
 
except ImportError:
16
 
    from httplib import HTTPSConnection
17
 
from logging import getLogger
18
 
from ntlm import ntlm
19
 
 
20
 
from urllib3 import HTTPSConnectionPool
21
 
 
22
 
 
23
 
log = getLogger(__name__)
24
 
 
25
 
 
26
 
class NTLMConnectionPool(HTTPSConnectionPool):
27
 
    """
28
 
    Implements an NTLM authentication version of an urllib3 connection pool
29
 
    """
30
 
 
31
 
    scheme = 'https'
32
 
 
33
 
    def __init__(self, user, pw, authurl, *args, **kwargs):
34
 
        """
35
 
        authurl is a random URL on the server that is protected by NTLM.
36
 
        user is the Windows user, probably in the DOMAIN\username format.
37
 
        pw is the password for the user.
38
 
        """
39
 
        super(NTLMConnectionPool, self).__init__(*args, **kwargs)
40
 
        self.authurl = authurl
41
 
        self.rawuser = user
42
 
        user_parts = user.split('\\', 1)
43
 
        self.domain = user_parts[0].upper()
44
 
        self.user = user_parts[1]
45
 
        self.pw = pw
46
 
 
47
 
    def _new_conn(self):
48
 
        # Performs the NTLM handshake that secures the connection. The socket
49
 
        # must be kept open while requests are performed.
50
 
        self.num_connections += 1
51
 
        log.debug('Starting NTLM HTTPS connection no. %d: https://%s%s' %
52
 
                  (self.num_connections, self.host, self.authurl))
53
 
 
54
 
        headers = {}
55
 
        headers['Connection'] = 'Keep-Alive'
56
 
        req_header = 'Authorization'
57
 
        resp_header = 'www-authenticate'
58
 
 
59
 
        conn = HTTPSConnection(host=self.host, port=self.port)
60
 
 
61
 
        # Send negotiation message
62
 
        headers[req_header] = (
63
 
            'NTLM %s' % ntlm.create_NTLM_NEGOTIATE_MESSAGE(self.rawuser))
64
 
        log.debug('Request headers: %s' % headers)
65
 
        conn.request('GET', self.authurl, None, headers)
66
 
        res = conn.getresponse()
67
 
        reshdr = dict(res.getheaders())
68
 
        log.debug('Response status: %s %s' % (res.status, res.reason))
69
 
        log.debug('Response headers: %s' % reshdr)
70
 
        log.debug('Response data: %s [...]' % res.read(100))
71
 
 
72
 
        # Remove the reference to the socket, so that it can not be closed by
73
 
        # the response object (we want to keep the socket open)
74
 
        res.fp = None
75
 
 
76
 
        # Server should respond with a challenge message
77
 
        auth_header_values = reshdr[resp_header].split(', ')
78
 
        auth_header_value = None
79
 
        for s in auth_header_values:
80
 
            if s[:5] == 'NTLM ':
81
 
                auth_header_value = s[5:]
82
 
        if auth_header_value is None:
83
 
            raise Exception('Unexpected %s response header: %s' %
84
 
                            (resp_header, reshdr[resp_header]))
85
 
 
86
 
        # Send authentication message
87
 
        ServerChallenge, NegotiateFlags = \
88
 
            ntlm.parse_NTLM_CHALLENGE_MESSAGE(auth_header_value)
89
 
        auth_msg = ntlm.create_NTLM_AUTHENTICATE_MESSAGE(ServerChallenge,
90
 
                                                         self.user,
91
 
                                                         self.domain,
92
 
                                                         self.pw,
93
 
                                                         NegotiateFlags)
94
 
        headers[req_header] = 'NTLM %s' % auth_msg
95
 
        log.debug('Request headers: %s' % headers)
96
 
        conn.request('GET', self.authurl, None, headers)
97
 
        res = conn.getresponse()
98
 
        log.debug('Response status: %s %s' % (res.status, res.reason))
99
 
        log.debug('Response headers: %s' % dict(res.getheaders()))
100
 
        log.debug('Response data: %s [...]' % res.read()[:100])
101
 
        if res.status != 200:
102
 
            if res.status == 401:
103
 
                raise Exception('Server rejected request: wrong '
104
 
                                'username or password')
105
 
            raise Exception('Wrong server response: %s %s' %
106
 
                            (res.status, res.reason))
107
 
 
108
 
        res.fp = None
109
 
        log.debug('Connection established')
110
 
        return conn
111
 
 
112
 
    def urlopen(self, method, url, body=None, headers=None, retries=3,
113
 
                redirect=True, assert_same_host=True):
114
 
        if headers is None:
115
 
            headers = {}
116
 
        headers['Connection'] = 'Keep-Alive'
117
 
        return super(NTLMConnectionPool, self).urlopen(method, url, body,
118
 
                                                       headers, retries,
119
 
                                                       redirect,
120
 
                                                       assert_same_host)