/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
2052.3.2 by John Arbash Meinel
Change Copyright .. by Canonical to Copyright ... Canonical
1
# Copyright (C) 2005 Canonical Ltd
1887.1.1 by Adeodato Simó
Do not separate paragraphs in the copyright statement with blank lines,
2
#
1185.1.18 by Robert Collins
Lalo Martins remotebranch patch
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
1887.1.1 by Adeodato Simó
Do not separate paragraphs in the copyright statement with blank lines,
7
#
1185.1.18 by Robert Collins
Lalo Martins remotebranch patch
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
# GNU General Public License for more details.
1887.1.1 by Adeodato Simó
Do not separate paragraphs in the copyright statement with blank lines,
12
#
1185.1.18 by Robert Collins
Lalo Martins remotebranch patch
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
2004.1.28 by v.ladeuil+lp at free
Merge bzr.dev. Including http modifications by "smart" related code
17
from cStringIO import StringIO
2004.1.25 by v.ladeuil+lp at free
Shuffle http related test code. Hopefully it ends up at the right place :)
18
import errno
2420.1.11 by Vincent Ladeuil
Implement digest authentication. Test suite passes. Tested against apache-2.x.
19
import md5
2164.2.29 by Vincent Ladeuil
Test the http redirection at the request level even if it's not
20
import re
2420.1.11 by Vincent Ladeuil
Implement digest authentication. Test suite passes. Tested against apache-2.x.
21
import sha
2004.1.25 by v.ladeuil+lp at free
Shuffle http related test code. Hopefully it ends up at the right place :)
22
import socket
3111.1.7 by Vincent Ladeuil
Further refactoring.
23
import threading
2420.1.11 by Vincent Ladeuil
Implement digest authentication. Test suite passes. Tested against apache-2.x.
24
import time
2420.1.9 by Vincent Ladeuil
Refactor proxy and auth test classes. Tests failing for digest auth.
25
import urllib2
2213.1.1 by v.ladeuil+lp at free
Workaround SimpleHTTPRequestHandler.translate_path limitation in
26
import urlparse
1530.1.14 by Robert Collins
Remove duplicate web server from HTTPTestUtil.
27
3111.1.16 by Vincent Ladeuil
Fix more imports.
28
from bzrlib import (
3376.2.4 by Martin Pool
Remove every assert statement from bzrlib!
29
    errors,
3111.1.16 by Vincent Ladeuil
Fix more imports.
30
    tests,
31
    transport,
32
    )
2018.5.150 by Andrew Bennetts
Tidy imports in HTTPTestUtil.py
33
from bzrlib.smart import protocol
3111.1.16 by Vincent Ladeuil
Fix more imports.
34
from bzrlib.tests import http_server
35
36
37
class HTTPServerWithSmarts(http_server.HttpServer):
2004.1.28 by v.ladeuil+lp at free
Merge bzr.dev. Including http modifications by "smart" related code
38
    """HTTPServerWithSmarts extends the HttpServer with POST methods that will
39
    trigger a smart server to execute with a transport rooted at the rootdir of
40
    the HTTP server.
41
    """
42
3111.1.25 by Vincent Ladeuil
Fix the smart server failing test and use it against protocol combinations.
43
    def __init__(self, protocol_version=None):
44
        http_server.HttpServer.__init__(self, SmartRequestHandler,
45
                                        protocol_version=protocol_version)
3111.1.16 by Vincent Ladeuil
Fix more imports.
46
47
48
class SmartRequestHandler(http_server.TestingHTTPRequestHandler):
2004.1.28 by v.ladeuil+lp at free
Merge bzr.dev. Including http modifications by "smart" related code
49
    """Extend TestingHTTPRequestHandler to support smart client POSTs."""
50
51
    def do_POST(self):
52
        """Hand the request off to a smart server instance."""
53
        self.send_response(200)
54
        self.send_header("Content-type", "application/octet-stream")
3111.1.16 by Vincent Ladeuil
Fix more imports.
55
        t = transport.get_transport(self.server.test_case_server._home_dir)
2004.1.28 by v.ladeuil+lp at free
Merge bzr.dev. Including http modifications by "smart" related code
56
        # TODO: We might like to support streaming responses.  1.0 allows no
57
        # Content-length in this case, so for integrity we should perform our
58
        # own chunking within the stream.
59
        # 1.1 allows chunked responses, and in this case we could chunk using
60
        # the HTTP chunking as this will allow HTTP persistence safely, even if
61
        # we have to stop early due to error, but we would also have to use the
62
        # HTTP trailer facility which may not be widely available.
63
        out_buffer = StringIO()
2018.5.150 by Andrew Bennetts
Tidy imports in HTTPTestUtil.py
64
        smart_protocol_request = protocol.SmartServerRequestProtocolOne(
3111.1.16 by Vincent Ladeuil
Fix more imports.
65
                t, out_buffer.write)
2004.1.28 by v.ladeuil+lp at free
Merge bzr.dev. Including http modifications by "smart" related code
66
        # if this fails, we should return 400 bad request, but failure is
67
        # failure for now - RBC 20060919
68
        data_length = int(self.headers['Content-Length'])
69
        # Perhaps there should be a SmartServerHTTPMedium that takes care of
70
        # feeding the bytes in the http request to the smart_protocol_request,
71
        # but for now it's simpler to just feed the bytes directly.
72
        smart_protocol_request.accept_bytes(self.rfile.read(data_length))
3376.2.4 by Martin Pool
Remove every assert statement from bzrlib!
73
        if not (smart_protocol_request.next_read_size() == 0):
74
            raise errors.SmartProtocolError(
75
                "not finished reading, but all data sent to protocol.")
2004.1.28 by v.ladeuil+lp at free
Merge bzr.dev. Including http modifications by "smart" related code
76
        self.send_header("Content-Length", str(len(out_buffer.getvalue())))
77
        self.end_headers()
78
        self.wfile.write(out_buffer.getvalue())
79
80
3111.1.16 by Vincent Ladeuil
Fix more imports.
81
class TestCaseWithWebserver(tests.TestCaseWithTransport):
1534.4.50 by Robert Collins
Got the bzrdir api straightened out, plenty of refactoring to use it pending, but the api is up and running.
82
    """A support class that provides readonly urls that are http://.
83
2004.3.3 by vila
Better (but still incomplete) design for bogus servers.
84
    This is done by forcing the readonly server to be an http
85
    one. This will currently fail if the primary transport is not
86
    backed by regular disk files.
1185.1.18 by Robert Collins
Lalo Martins remotebranch patch
87
    """
88
    def setUp(self):
1530.1.14 by Robert Collins
Remove duplicate web server from HTTPTestUtil.
89
        super(TestCaseWithWebserver, self).setUp()
3111.1.16 by Vincent Ladeuil
Fix more imports.
90
        self.transport_readonly_server = http_server.HttpServer
2167.3.5 by v.ladeuil+lp at free
Tests for proxies, covering #74759.
91
92
93
class TestCaseWithTwoWebservers(TestCaseWithWebserver):
2164.2.13 by v.ladeuil+lp at free
Add tests for redirection. Preserve transport decorations.
94
    """A support class providing readonly urls on two servers that are http://.
2167.3.5 by v.ladeuil+lp at free
Tests for proxies, covering #74759.
95
2164.2.25 by Vincent Ladeuil
Fix typos noticed by Aaron.
96
    We set up two webservers to allows various tests involving
2167.3.5 by v.ladeuil+lp at free
Tests for proxies, covering #74759.
97
    proxies or redirections from one server to the other.
98
    """
99
    def setUp(self):
100
        super(TestCaseWithTwoWebservers, self).setUp()
3111.1.16 by Vincent Ladeuil
Fix more imports.
101
        self.transport_secondary_server = http_server.HttpServer
2167.3.5 by v.ladeuil+lp at free
Tests for proxies, covering #74759.
102
        self.__secondary_server = None
103
104
    def create_transport_secondary_server(self):
105
        """Create a transport server from class defined at init.
106
107
        This is mostly a hook for daughter classes.
108
        """
109
        return self.transport_secondary_server()
110
111
    def get_secondary_server(self):
112
        """Get the server instance for the secondary transport."""
113
        if self.__secondary_server is None:
114
            self.__secondary_server = self.create_transport_secondary_server()
115
            self.__secondary_server.setUp()
116
            self.addCleanup(self.__secondary_server.tearDown)
117
        return self.__secondary_server
118
119
3111.1.16 by Vincent Ladeuil
Fix more imports.
120
class ProxyServer(http_server.HttpServer):
2420.1.9 by Vincent Ladeuil
Refactor proxy and auth test classes. Tests failing for digest auth.
121
    """A proxy test server for http transports."""
122
123
    proxy_requests = True
2213.1.1 by v.ladeuil+lp at free
Workaround SimpleHTTPRequestHandler.translate_path limitation in
124
2167.3.5 by v.ladeuil+lp at free
Tests for proxies, covering #74759.
125
3111.1.16 by Vincent Ladeuil
Fix more imports.
126
class RedirectRequestHandler(http_server.TestingHTTPRequestHandler):
2164.2.13 by v.ladeuil+lp at free
Add tests for redirection. Preserve transport decorations.
127
    """Redirect all request to the specified server"""
128
129
    def parse_request(self):
130
        """Redirect a single HTTP request to another host"""
3111.1.16 by Vincent Ladeuil
Fix more imports.
131
        valid = http_server.TestingHTTPRequestHandler.parse_request(self)
2164.2.13 by v.ladeuil+lp at free
Add tests for redirection. Preserve transport decorations.
132
        if valid:
2164.2.29 by Vincent Ladeuil
Test the http redirection at the request level even if it's not
133
            tcs = self.server.test_case_server
134
            code, target = tcs.is_redirected(self.path)
135
            if code is not None and target is not None:
136
                # Redirect as instructed
137
                self.send_response(code)
2164.2.16 by Vincent Ladeuil
Add tests.
138
                self.send_header('Location', target)
3111.1.20 by Vincent Ladeuil
Make all the test pass. Looks like we are HTTP/1.1 compliant.
139
                # We do not send a body
140
                self.send_header('Content-Length', '0')
2164.2.16 by Vincent Ladeuil
Add tests.
141
                self.end_headers()
142
                return False # The job is done
2164.2.29 by Vincent Ladeuil
Test the http redirection at the request level even if it's not
143
            else:
144
                # We leave the parent class serve the request
145
                pass
2164.2.13 by v.ladeuil+lp at free
Add tests for redirection. Preserve transport decorations.
146
        return valid
147
148
3111.1.16 by Vincent Ladeuil
Fix more imports.
149
class HTTPServerRedirecting(http_server.HttpServer):
2164.2.13 by v.ladeuil+lp at free
Add tests for redirection. Preserve transport decorations.
150
    """An HttpServer redirecting to another server """
151
3111.1.18 by Vincent Ladeuil
Test parametrization for protocol versions achieved. Tests are failing :)
152
    def __init__(self, request_handler=RedirectRequestHandler,
153
                 protocol_version=None):
154
        http_server.HttpServer.__init__(self, request_handler,
155
                                        protocol_version=protocol_version)
2164.2.29 by Vincent Ladeuil
Test the http redirection at the request level even if it's not
156
        # redirections is a list of tuples (source, target, code)
157
        # - source is a regexp for the paths requested
158
        # - target is a replacement for re.sub describing where
159
        #   the request will be redirected
160
        # - code is the http error code associated to the
161
        #   redirection (301 permanent, 302 temporarry, etc
162
        self.redirections = []
163
164
    def redirect_to(self, host, port):
165
        """Redirect all requests to a specific host:port"""
166
        self.redirections = [('(.*)',
167
                              r'http://%s:%s\1' % (host, port) ,
168
                              301)]
169
170
    def is_redirected(self, path):
171
        """Is the path redirected by this server.
172
173
        :param path: the requested relative path
174
175
        :returns: a tuple (code, target) if a matching
176
             redirection is found, (None, None) otherwise.
177
        """
178
        code = None
179
        target = None
180
        for (rsource, rtarget, rcode) in self.redirections:
181
            target, match = re.subn(rsource, rtarget, path)
182
            if match:
183
                code = rcode
184
                break # The first match wins
185
            else:
186
                target = None
187
        return code, target
2164.2.13 by v.ladeuil+lp at free
Add tests for redirection. Preserve transport decorations.
188
2167.3.5 by v.ladeuil+lp at free
Tests for proxies, covering #74759.
189
2164.2.22 by Vincent Ladeuil
Take Aaron's review comments into account.
190
class TestCaseWithRedirectedWebserver(TestCaseWithTwoWebservers):
191
   """A support class providing redirections from one server to another.
192
2164.2.25 by Vincent Ladeuil
Fix typos noticed by Aaron.
193
   We set up two webservers to allows various tests involving
2164.2.22 by Vincent Ladeuil
Take Aaron's review comments into account.
194
   redirections.
195
   The 'old' server is redirected to the 'new' server.
196
   """
197
198
   def create_transport_secondary_server(self):
199
       """Create the secondary server redirecting to the primary server"""
200
       new = self.get_readonly_server()
201
       redirecting = HTTPServerRedirecting()
202
       redirecting.redirect_to(new.host, new.port)
203
       return redirecting
204
205
   def setUp(self):
206
       super(TestCaseWithRedirectedWebserver, self).setUp()
207
       # The redirections will point to the new server
208
       self.new_server = self.get_readonly_server()
209
       # The requests to the old server will be redirected
210
       self.old_server = self.get_secondary_server()
211
212
3111.1.16 by Vincent Ladeuil
Fix more imports.
213
class AuthRequestHandler(http_server.TestingHTTPRequestHandler):
2420.1.9 by Vincent Ladeuil
Refactor proxy and auth test classes. Tests failing for digest auth.
214
    """Requires an authentication to process requests.
2363.4.12 by Vincent Ladeuil
Take jam's review comments into account. Fix typos, give better
215
216
    This is intended to be used with a server that always and
2420.1.9 by Vincent Ladeuil
Refactor proxy and auth test classes. Tests failing for digest auth.
217
    only use one authentication scheme (implemented by daughter
218
    classes).
2363.4.12 by Vincent Ladeuil
Take jam's review comments into account. Fix typos, give better
219
    """
2363.4.8 by Vincent Ladeuil
Implement a basic auth HTTP server, rewrite tests accordingly.
220
2420.1.9 by Vincent Ladeuil
Refactor proxy and auth test classes. Tests failing for digest auth.
221
    # The following attributes should be defined in the server
2420.1.10 by Vincent Ladeuil
Doc fixes.
222
    # - auth_header_sent: the header name sent to require auth
223
    # - auth_header_recv: the header received containing auth
224
    # - auth_error_code: the error code to indicate auth required
2420.1.2 by Vincent Ladeuil
Define tests for http proxy basic authentication. They fail.
225
2363.4.8 by Vincent Ladeuil
Implement a basic auth HTTP server, rewrite tests accordingly.
226
    def do_GET(self):
2420.1.9 by Vincent Ladeuil
Refactor proxy and auth test classes. Tests failing for digest auth.
227
        if self.authorized():
3111.1.16 by Vincent Ladeuil
Fix more imports.
228
            return http_server.TestingHTTPRequestHandler.do_GET(self)
2420.1.9 by Vincent Ladeuil
Refactor proxy and auth test classes. Tests failing for digest auth.
229
        else:
230
            # Note that we must update test_case_server *before*
231
            # sending the error or the client may try to read it
232
            # before we have sent the whole error back.
233
            tcs = self.server.test_case_server
234
            tcs.auth_required_errors += 1
235
            self.send_response(tcs.auth_error_code)
236
            self.send_header_auth_reqed()
3111.1.20 by Vincent Ladeuil
Make all the test pass. Looks like we are HTTP/1.1 compliant.
237
            # We do not send a body
238
            self.send_header('Content-Length', '0')
2420.1.9 by Vincent Ladeuil
Refactor proxy and auth test classes. Tests failing for digest auth.
239
            self.end_headers()
240
            return
2363.4.8 by Vincent Ladeuil
Implement a basic auth HTTP server, rewrite tests accordingly.
241
2363.4.12 by Vincent Ladeuil
Take jam's review comments into account. Fix typos, give better
242
2420.1.9 by Vincent Ladeuil
Refactor proxy and auth test classes. Tests failing for digest auth.
243
class BasicAuthRequestHandler(AuthRequestHandler):
244
    """Implements the basic authentication of a request"""
245
246
    def authorized(self):
247
        tcs = self.server.test_case_server
248
        if tcs.auth_scheme != 'basic':
249
            return False
250
2420.1.11 by Vincent Ladeuil
Implement digest authentication. Test suite passes. Tested against apache-2.x.
251
        auth_header = self.headers.get(tcs.auth_header_recv, None)
252
        if auth_header:
253
            scheme, raw_auth = auth_header.split(' ', 1)
254
            if scheme.lower() == tcs.auth_scheme:
255
                user, password = raw_auth.decode('base64').split(':')
256
                return tcs.authorized(user, password)
2420.1.9 by Vincent Ladeuil
Refactor proxy and auth test classes. Tests failing for digest auth.
257
258
        return False
259
260
    def send_header_auth_reqed(self):
2420.1.11 by Vincent Ladeuil
Implement digest authentication. Test suite passes. Tested against apache-2.x.
261
        tcs = self.server.test_case_server
262
        self.send_header(tcs.auth_header_sent,
263
                         'Basic realm="%s"' % tcs.auth_realm)
264
265
2420.1.19 by Vincent Ladeuil
Cosmetic changes.
266
# FIXME: We could send an Authentication-Info header too when
267
# the authentication is succesful
2420.1.9 by Vincent Ladeuil
Refactor proxy and auth test classes. Tests failing for digest auth.
268
269
class DigestAuthRequestHandler(AuthRequestHandler):
2420.1.11 by Vincent Ladeuil
Implement digest authentication. Test suite passes. Tested against apache-2.x.
270
    """Implements the digest authentication of a request.
271
272
    We need persistence for some attributes and that can't be
273
    achieved here since we get instantiated for each request. We
274
    rely on the DigestAuthServer to take care of them.
275
    """
2420.1.9 by Vincent Ladeuil
Refactor proxy and auth test classes. Tests failing for digest auth.
276
277
    def authorized(self):
278
        tcs = self.server.test_case_server
279
        if tcs.auth_scheme != 'digest':
280
            return False
281
2420.1.11 by Vincent Ladeuil
Implement digest authentication. Test suite passes. Tested against apache-2.x.
282
        auth_header = self.headers.get(tcs.auth_header_recv, None)
283
        if auth_header is None:
284
            return False
285
        scheme, auth = auth_header.split(None, 1)
286
        if scheme.lower() == tcs.auth_scheme:
287
            auth_dict = urllib2.parse_keqv_list(urllib2.parse_http_list(auth))
288
289
            return tcs.digest_authorized(auth_dict, self.command)
2420.1.9 by Vincent Ladeuil
Refactor proxy and auth test classes. Tests failing for digest auth.
290
291
        return False
292
293
    def send_header_auth_reqed(self):
2420.1.11 by Vincent Ladeuil
Implement digest authentication. Test suite passes. Tested against apache-2.x.
294
        tcs = self.server.test_case_server
295
        header = 'Digest realm="%s", ' % tcs.auth_realm
2545.2.1 by Vincent Ladeuil
Fix 121889 by working around urllib2 bug.
296
        header += 'nonce="%s", algorithm="%s", qop="auth"' % (tcs.auth_nonce,
297
                                                              'MD5')
2420.1.11 by Vincent Ladeuil
Implement digest authentication. Test suite passes. Tested against apache-2.x.
298
        self.send_header(tcs.auth_header_sent,header)
299
2420.1.9 by Vincent Ladeuil
Refactor proxy and auth test classes. Tests failing for digest auth.
300
3111.1.16 by Vincent Ladeuil
Fix more imports.
301
class AuthServer(http_server.HttpServer):
2420.1.9 by Vincent Ladeuil
Refactor proxy and auth test classes. Tests failing for digest auth.
302
    """Extends HttpServer with a dictionary of passwords.
303
304
    This is used as a base class for various schemes which should
305
    all use or redefined the associated AuthRequestHandler.
2363.4.12 by Vincent Ladeuil
Take jam's review comments into account. Fix typos, give better
306
307
    Note that no users are defined by default, so add_user should
308
    be called before issuing the first request.
2420.1.11 by Vincent Ladeuil
Implement digest authentication. Test suite passes. Tested against apache-2.x.
309
    """
2420.1.9 by Vincent Ladeuil
Refactor proxy and auth test classes. Tests failing for digest auth.
310
311
    # The following attributes should be set dy daughter classes
312
    # and are used by AuthRequestHandler.
313
    auth_header_sent = None
314
    auth_header_recv = None
315
    auth_error_code = None
2420.1.11 by Vincent Ladeuil
Implement digest authentication. Test suite passes. Tested against apache-2.x.
316
    auth_realm = "Thou should not pass"
2363.4.12 by Vincent Ladeuil
Take jam's review comments into account. Fix typos, give better
317
3111.1.18 by Vincent Ladeuil
Test parametrization for protocol versions achieved. Tests are failing :)
318
    def __init__(self, request_handler, auth_scheme,
319
                 protocol_version=None):
320
        http_server.HttpServer.__init__(self, request_handler,
321
                                        protocol_version=protocol_version)
2363.4.12 by Vincent Ladeuil
Take jam's review comments into account. Fix typos, give better
322
        self.auth_scheme = auth_scheme
2363.4.8 by Vincent Ladeuil
Implement a basic auth HTTP server, rewrite tests accordingly.
323
        self.password_of = {}
2420.1.4 by Vincent Ladeuil
Add test checking the number of roundtrips due to 401 or 407 errors.
324
        self.auth_required_errors = 0
2363.4.8 by Vincent Ladeuil
Implement a basic auth HTTP server, rewrite tests accordingly.
325
326
    def add_user(self, user, password):
2363.4.12 by Vincent Ladeuil
Take jam's review comments into account. Fix typos, give better
327
        """Declare a user with an associated password.
328
329
        password can be empty, use an empty string ('') in that
330
        case, not None.
331
        """
2363.4.8 by Vincent Ladeuil
Implement a basic auth HTTP server, rewrite tests accordingly.
332
        self.password_of[user] = password
333
334
    def authorized(self, user, password):
2420.1.11 by Vincent Ladeuil
Implement digest authentication. Test suite passes. Tested against apache-2.x.
335
        """Check that the given user provided the right password"""
2363.4.12 by Vincent Ladeuil
Take jam's review comments into account. Fix typos, give better
336
        expected_password = self.password_of.get(user, None)
337
        return expected_password is not None and password == expected_password
338
339
2420.1.19 by Vincent Ladeuil
Cosmetic changes.
340
# FIXME: There is some code duplication with
2900.2.5 by Vincent Ladeuil
ake ftp aware of authentication config.
341
# _urllib2_wrappers.py.DigestAuthHandler. If that duplication
2420.1.19 by Vincent Ladeuil
Cosmetic changes.
342
# grows, it may require a refactoring. Also, we don't implement
343
# SHA algorithm nor MD5-sess here, but that does not seem worth
344
# it.
2420.1.11 by Vincent Ladeuil
Implement digest authentication. Test suite passes. Tested against apache-2.x.
345
class DigestAuthServer(AuthServer):
346
    """A digest authentication server"""
347
2420.1.16 by Vincent Ladeuil
Handle nonce changes. Fix a nasty bug breaking the auth parameters sharing.
348
    auth_nonce = 'now!'
2420.1.11 by Vincent Ladeuil
Implement digest authentication. Test suite passes. Tested against apache-2.x.
349
3111.1.18 by Vincent Ladeuil
Test parametrization for protocol versions achieved. Tests are failing :)
350
    def __init__(self, request_handler, auth_scheme,
351
                 protocol_version=None):
352
        AuthServer.__init__(self, request_handler, auth_scheme,
353
                            protocol_version=protocol_version)
2420.1.11 by Vincent Ladeuil
Implement digest authentication. Test suite passes. Tested against apache-2.x.
354
355
    def digest_authorized(self, auth, command):
2420.1.16 by Vincent Ladeuil
Handle nonce changes. Fix a nasty bug breaking the auth parameters sharing.
356
        nonce = auth['nonce']
357
        if nonce != self.auth_nonce:
358
            return False
2420.1.11 by Vincent Ladeuil
Implement digest authentication. Test suite passes. Tested against apache-2.x.
359
        realm = auth['realm']
360
        if realm != self.auth_realm:
361
            return False
362
        user = auth['username']
363
        if not self.password_of.has_key(user):
364
            return False
365
        algorithm= auth['algorithm']
366
        if algorithm != 'MD5':
367
            return False
368
        qop = auth['qop']
369
        if qop != 'auth':
370
            return False
371
372
        password = self.password_of[user]
373
374
        # Recalculate the response_digest to compare with the one
375
        # sent by the client
376
        A1 = '%s:%s:%s' % (user, realm, password)
377
        A2 = '%s:%s' % (command, auth['uri'])
378
379
        H = lambda x: md5.new(x).hexdigest()
380
        KD = lambda secret, data: H("%s:%s" % (secret, data))
381
382
        nonce_count = int(auth['nc'], 16)
383
384
        ncvalue = '%08x' % nonce_count
385
386
        cnonce = auth['cnonce']
387
        noncebit = '%s:%s:%s:%s:%s' % (nonce, ncvalue, cnonce, qop, H(A2))
388
        response_digest = KD(H(A1), noncebit)
389
390
        return response_digest == auth['response']
391
2420.1.9 by Vincent Ladeuil
Refactor proxy and auth test classes. Tests failing for digest auth.
392
class HTTPAuthServer(AuthServer):
393
    """An HTTP server requiring authentication"""
394
2420.1.11 by Vincent Ladeuil
Implement digest authentication. Test suite passes. Tested against apache-2.x.
395
    def init_http_auth(self):
396
        self.auth_header_sent = 'WWW-Authenticate'
397
        self.auth_header_recv = 'Authorization'
398
        self.auth_error_code = 401
2420.1.9 by Vincent Ladeuil
Refactor proxy and auth test classes. Tests failing for digest auth.
399
400
401
class ProxyAuthServer(AuthServer):
402
    """A proxy server requiring authentication"""
403
2420.1.11 by Vincent Ladeuil
Implement digest authentication. Test suite passes. Tested against apache-2.x.
404
    def init_proxy_auth(self):
405
        self.proxy_requests = True
406
        self.auth_header_sent = 'Proxy-Authenticate'
407
        self.auth_header_recv = 'Proxy-Authorization'
408
        self.auth_error_code = 407
2420.1.9 by Vincent Ladeuil
Refactor proxy and auth test classes. Tests failing for digest auth.
409
410
411
class HTTPBasicAuthServer(HTTPAuthServer):
412
    """An HTTP server requiring basic authentication"""
413
3111.1.18 by Vincent Ladeuil
Test parametrization for protocol versions achieved. Tests are failing :)
414
    def __init__(self, protocol_version=None):
415
        HTTPAuthServer.__init__(self, BasicAuthRequestHandler, 'basic',
416
                                protocol_version=protocol_version)
2420.1.11 by Vincent Ladeuil
Implement digest authentication. Test suite passes. Tested against apache-2.x.
417
        self.init_http_auth()
418
419
420
class HTTPDigestAuthServer(DigestAuthServer, HTTPAuthServer):
2420.1.9 by Vincent Ladeuil
Refactor proxy and auth test classes. Tests failing for digest auth.
421
    """An HTTP server requiring digest authentication"""
422
3111.1.18 by Vincent Ladeuil
Test parametrization for protocol versions achieved. Tests are failing :)
423
    def __init__(self, protocol_version=None):
424
        DigestAuthServer.__init__(self, DigestAuthRequestHandler, 'digest',
425
                                  protocol_version=protocol_version)
2420.1.11 by Vincent Ladeuil
Implement digest authentication. Test suite passes. Tested against apache-2.x.
426
        self.init_http_auth()
2420.1.9 by Vincent Ladeuil
Refactor proxy and auth test classes. Tests failing for digest auth.
427
428
429
class ProxyBasicAuthServer(ProxyAuthServer):
2420.1.11 by Vincent Ladeuil
Implement digest authentication. Test suite passes. Tested against apache-2.x.
430
    """A proxy server requiring basic authentication"""
2420.1.9 by Vincent Ladeuil
Refactor proxy and auth test classes. Tests failing for digest auth.
431
3111.1.18 by Vincent Ladeuil
Test parametrization for protocol versions achieved. Tests are failing :)
432
    def __init__(self, protocol_version=None):
433
        ProxyAuthServer.__init__(self, BasicAuthRequestHandler, 'basic',
434
                                 protocol_version=protocol_version)
2420.1.11 by Vincent Ladeuil
Implement digest authentication. Test suite passes. Tested against apache-2.x.
435
        self.init_proxy_auth()
436
437
438
class ProxyDigestAuthServer(DigestAuthServer, ProxyAuthServer):
439
    """A proxy server requiring basic authentication"""
2420.1.9 by Vincent Ladeuil
Refactor proxy and auth test classes. Tests failing for digest auth.
440
3111.1.18 by Vincent Ladeuil
Test parametrization for protocol versions achieved. Tests are failing :)
441
    def __init__(self, protocol_version=None):
442
        ProxyAuthServer.__init__(self, DigestAuthRequestHandler, 'digest',
443
                                 protocol_version=protocol_version)
2420.1.11 by Vincent Ladeuil
Implement digest authentication. Test suite passes. Tested against apache-2.x.
444
        self.init_proxy_auth()
2420.1.9 by Vincent Ladeuil
Refactor proxy and auth test classes. Tests failing for digest auth.
445
446