/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
29
from bzrlib import (
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))
73
        assert smart_protocol_request.next_read_size() == 0, (
74
            "not finished reading, but all data sent to protocol.")
75
        self.send_header("Content-Length", str(len(out_buffer.getvalue())))
76
        self.end_headers()
77
        self.wfile.write(out_buffer.getvalue())
78
79
3111.1.16 by Vincent Ladeuil
Fix more imports.
80
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.
81
    """A support class that provides readonly urls that are http://.
82
2004.3.3 by vila
Better (but still incomplete) design for bogus servers.
83
    This is done by forcing the readonly server to be an http
84
    one. This will currently fail if the primary transport is not
85
    backed by regular disk files.
1185.1.18 by Robert Collins
Lalo Martins remotebranch patch
86
    """
87
    def setUp(self):
1530.1.14 by Robert Collins
Remove duplicate web server from HTTPTestUtil.
88
        super(TestCaseWithWebserver, self).setUp()
3111.1.16 by Vincent Ladeuil
Fix more imports.
89
        self.transport_readonly_server = http_server.HttpServer
2167.3.5 by v.ladeuil+lp at free
Tests for proxies, covering #74759.
90
91
92
class TestCaseWithTwoWebservers(TestCaseWithWebserver):
2164.2.13 by v.ladeuil+lp at free
Add tests for redirection. Preserve transport decorations.
93
    """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.
94
2164.2.25 by Vincent Ladeuil
Fix typos noticed by Aaron.
95
    We set up two webservers to allows various tests involving
2167.3.5 by v.ladeuil+lp at free
Tests for proxies, covering #74759.
96
    proxies or redirections from one server to the other.
97
    """
98
    def setUp(self):
99
        super(TestCaseWithTwoWebservers, self).setUp()
3111.1.16 by Vincent Ladeuil
Fix more imports.
100
        self.transport_secondary_server = http_server.HttpServer
2167.3.5 by v.ladeuil+lp at free
Tests for proxies, covering #74759.
101
        self.__secondary_server = None
102
103
    def create_transport_secondary_server(self):
104
        """Create a transport server from class defined at init.
105
106
        This is mostly a hook for daughter classes.
107
        """
108
        return self.transport_secondary_server()
109
110
    def get_secondary_server(self):
111
        """Get the server instance for the secondary transport."""
112
        if self.__secondary_server is None:
113
            self.__secondary_server = self.create_transport_secondary_server()
114
            self.__secondary_server.setUp()
115
            self.addCleanup(self.__secondary_server.tearDown)
116
        return self.__secondary_server
117
118
3111.1.16 by Vincent Ladeuil
Fix more imports.
119
class ProxyServer(http_server.HttpServer):
2420.1.9 by Vincent Ladeuil
Refactor proxy and auth test classes. Tests failing for digest auth.
120
    """A proxy test server for http transports."""
121
122
    proxy_requests = True
2213.1.1 by v.ladeuil+lp at free
Workaround SimpleHTTPRequestHandler.translate_path limitation in
123
2167.3.5 by v.ladeuil+lp at free
Tests for proxies, covering #74759.
124
3111.1.16 by Vincent Ladeuil
Fix more imports.
125
class RedirectRequestHandler(http_server.TestingHTTPRequestHandler):
2164.2.13 by v.ladeuil+lp at free
Add tests for redirection. Preserve transport decorations.
126
    """Redirect all request to the specified server"""
127
128
    def parse_request(self):
129
        """Redirect a single HTTP request to another host"""
3111.1.16 by Vincent Ladeuil
Fix more imports.
130
        valid = http_server.TestingHTTPRequestHandler.parse_request(self)
2164.2.13 by v.ladeuil+lp at free
Add tests for redirection. Preserve transport decorations.
131
        if valid:
2164.2.29 by Vincent Ladeuil
Test the http redirection at the request level even if it's not
132
            tcs = self.server.test_case_server
133
            code, target = tcs.is_redirected(self.path)
134
            if code is not None and target is not None:
135
                # Redirect as instructed
136
                self.send_response(code)
2164.2.16 by Vincent Ladeuil
Add tests.
137
                self.send_header('Location', target)
3111.1.20 by Vincent Ladeuil
Make all the test pass. Looks like we are HTTP/1.1 compliant.
138
                # We do not send a body
139
                self.send_header('Content-Length', '0')
2164.2.16 by Vincent Ladeuil
Add tests.
140
                self.end_headers()
141
                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
142
            else:
143
                # We leave the parent class serve the request
144
                pass
2164.2.13 by v.ladeuil+lp at free
Add tests for redirection. Preserve transport decorations.
145
        return valid
146
147
3111.1.16 by Vincent Ladeuil
Fix more imports.
148
class HTTPServerRedirecting(http_server.HttpServer):
2164.2.13 by v.ladeuil+lp at free
Add tests for redirection. Preserve transport decorations.
149
    """An HttpServer redirecting to another server """
150
3111.1.18 by Vincent Ladeuil
Test parametrization for protocol versions achieved. Tests are failing :)
151
    def __init__(self, request_handler=RedirectRequestHandler,
152
                 protocol_version=None):
153
        http_server.HttpServer.__init__(self, request_handler,
154
                                        protocol_version=protocol_version)
2164.2.29 by Vincent Ladeuil
Test the http redirection at the request level even if it's not
155
        # redirections is a list of tuples (source, target, code)
156
        # - source is a regexp for the paths requested
157
        # - target is a replacement for re.sub describing where
158
        #   the request will be redirected
159
        # - code is the http error code associated to the
160
        #   redirection (301 permanent, 302 temporarry, etc
161
        self.redirections = []
162
163
    def redirect_to(self, host, port):
164
        """Redirect all requests to a specific host:port"""
165
        self.redirections = [('(.*)',
166
                              r'http://%s:%s\1' % (host, port) ,
167
                              301)]
168
169
    def is_redirected(self, path):
170
        """Is the path redirected by this server.
171
172
        :param path: the requested relative path
173
174
        :returns: a tuple (code, target) if a matching
175
             redirection is found, (None, None) otherwise.
176
        """
177
        code = None
178
        target = None
179
        for (rsource, rtarget, rcode) in self.redirections:
180
            target, match = re.subn(rsource, rtarget, path)
181
            if match:
182
                code = rcode
183
                break # The first match wins
184
            else:
185
                target = None
186
        return code, target
2164.2.13 by v.ladeuil+lp at free
Add tests for redirection. Preserve transport decorations.
187
2167.3.5 by v.ladeuil+lp at free
Tests for proxies, covering #74759.
188
2164.2.22 by Vincent Ladeuil
Take Aaron's review comments into account.
189
class TestCaseWithRedirectedWebserver(TestCaseWithTwoWebservers):
190
   """A support class providing redirections from one server to another.
191
2164.2.25 by Vincent Ladeuil
Fix typos noticed by Aaron.
192
   We set up two webservers to allows various tests involving
2164.2.22 by Vincent Ladeuil
Take Aaron's review comments into account.
193
   redirections.
194
   The 'old' server is redirected to the 'new' server.
195
   """
196
197
   def create_transport_secondary_server(self):
198
       """Create the secondary server redirecting to the primary server"""
199
       new = self.get_readonly_server()
200
       redirecting = HTTPServerRedirecting()
201
       redirecting.redirect_to(new.host, new.port)
202
       return redirecting
203
204
   def setUp(self):
205
       super(TestCaseWithRedirectedWebserver, self).setUp()
206
       # The redirections will point to the new server
207
       self.new_server = self.get_readonly_server()
208
       # The requests to the old server will be redirected
209
       self.old_server = self.get_secondary_server()
210
211
3111.1.16 by Vincent Ladeuil
Fix more imports.
212
class AuthRequestHandler(http_server.TestingHTTPRequestHandler):
2420.1.9 by Vincent Ladeuil
Refactor proxy and auth test classes. Tests failing for digest auth.
213
    """Requires an authentication to process requests.
2363.4.12 by Vincent Ladeuil
Take jam's review comments into account. Fix typos, give better
214
215
    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.
216
    only use one authentication scheme (implemented by daughter
217
    classes).
2363.4.12 by Vincent Ladeuil
Take jam's review comments into account. Fix typos, give better
218
    """
2363.4.8 by Vincent Ladeuil
Implement a basic auth HTTP server, rewrite tests accordingly.
219
2420.1.9 by Vincent Ladeuil
Refactor proxy and auth test classes. Tests failing for digest auth.
220
    # The following attributes should be defined in the server
2420.1.10 by Vincent Ladeuil
Doc fixes.
221
    # - auth_header_sent: the header name sent to require auth
222
    # - auth_header_recv: the header received containing auth
223
    # - 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.
224
2363.4.8 by Vincent Ladeuil
Implement a basic auth HTTP server, rewrite tests accordingly.
225
    def do_GET(self):
2420.1.9 by Vincent Ladeuil
Refactor proxy and auth test classes. Tests failing for digest auth.
226
        if self.authorized():
3111.1.16 by Vincent Ladeuil
Fix more imports.
227
            return http_server.TestingHTTPRequestHandler.do_GET(self)
2420.1.9 by Vincent Ladeuil
Refactor proxy and auth test classes. Tests failing for digest auth.
228
        else:
229
            # Note that we must update test_case_server *before*
230
            # sending the error or the client may try to read it
231
            # before we have sent the whole error back.
232
            tcs = self.server.test_case_server
233
            tcs.auth_required_errors += 1
234
            self.send_response(tcs.auth_error_code)
235
            self.send_header_auth_reqed()
3111.1.20 by Vincent Ladeuil
Make all the test pass. Looks like we are HTTP/1.1 compliant.
236
            # We do not send a body
237
            self.send_header('Content-Length', '0')
2420.1.9 by Vincent Ladeuil
Refactor proxy and auth test classes. Tests failing for digest auth.
238
            self.end_headers()
239
            return
2363.4.8 by Vincent Ladeuil
Implement a basic auth HTTP server, rewrite tests accordingly.
240
2363.4.12 by Vincent Ladeuil
Take jam's review comments into account. Fix typos, give better
241
2420.1.9 by Vincent Ladeuil
Refactor proxy and auth test classes. Tests failing for digest auth.
242
class BasicAuthRequestHandler(AuthRequestHandler):
243
    """Implements the basic authentication of a request"""
244
245
    def authorized(self):
246
        tcs = self.server.test_case_server
247
        if tcs.auth_scheme != 'basic':
248
            return False
249
2420.1.11 by Vincent Ladeuil
Implement digest authentication. Test suite passes. Tested against apache-2.x.
250
        auth_header = self.headers.get(tcs.auth_header_recv, None)
251
        if auth_header:
252
            scheme, raw_auth = auth_header.split(' ', 1)
253
            if scheme.lower() == tcs.auth_scheme:
254
                user, password = raw_auth.decode('base64').split(':')
255
                return tcs.authorized(user, password)
2420.1.9 by Vincent Ladeuil
Refactor proxy and auth test classes. Tests failing for digest auth.
256
257
        return False
258
259
    def send_header_auth_reqed(self):
2420.1.11 by Vincent Ladeuil
Implement digest authentication. Test suite passes. Tested against apache-2.x.
260
        tcs = self.server.test_case_server
261
        self.send_header(tcs.auth_header_sent,
262
                         'Basic realm="%s"' % tcs.auth_realm)
263
264
2420.1.19 by Vincent Ladeuil
Cosmetic changes.
265
# FIXME: We could send an Authentication-Info header too when
266
# the authentication is succesful
2420.1.9 by Vincent Ladeuil
Refactor proxy and auth test classes. Tests failing for digest auth.
267
268
class DigestAuthRequestHandler(AuthRequestHandler):
2420.1.11 by Vincent Ladeuil
Implement digest authentication. Test suite passes. Tested against apache-2.x.
269
    """Implements the digest authentication of a request.
270
271
    We need persistence for some attributes and that can't be
272
    achieved here since we get instantiated for each request. We
273
    rely on the DigestAuthServer to take care of them.
274
    """
2420.1.9 by Vincent Ladeuil
Refactor proxy and auth test classes. Tests failing for digest auth.
275
276
    def authorized(self):
277
        tcs = self.server.test_case_server
278
        if tcs.auth_scheme != 'digest':
279
            return False
280
2420.1.11 by Vincent Ladeuil
Implement digest authentication. Test suite passes. Tested against apache-2.x.
281
        auth_header = self.headers.get(tcs.auth_header_recv, None)
282
        if auth_header is None:
283
            return False
284
        scheme, auth = auth_header.split(None, 1)
285
        if scheme.lower() == tcs.auth_scheme:
286
            auth_dict = urllib2.parse_keqv_list(urllib2.parse_http_list(auth))
287
288
            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.
289
290
        return False
291
292
    def send_header_auth_reqed(self):
2420.1.11 by Vincent Ladeuil
Implement digest authentication. Test suite passes. Tested against apache-2.x.
293
        tcs = self.server.test_case_server
294
        header = 'Digest realm="%s", ' % tcs.auth_realm
2545.2.1 by Vincent Ladeuil
Fix 121889 by working around urllib2 bug.
295
        header += 'nonce="%s", algorithm="%s", qop="auth"' % (tcs.auth_nonce,
296
                                                              'MD5')
2420.1.11 by Vincent Ladeuil
Implement digest authentication. Test suite passes. Tested against apache-2.x.
297
        self.send_header(tcs.auth_header_sent,header)
298
2420.1.9 by Vincent Ladeuil
Refactor proxy and auth test classes. Tests failing for digest auth.
299
3111.1.16 by Vincent Ladeuil
Fix more imports.
300
class AuthServer(http_server.HttpServer):
2420.1.9 by Vincent Ladeuil
Refactor proxy and auth test classes. Tests failing for digest auth.
301
    """Extends HttpServer with a dictionary of passwords.
302
303
    This is used as a base class for various schemes which should
304
    all use or redefined the associated AuthRequestHandler.
2363.4.12 by Vincent Ladeuil
Take jam's review comments into account. Fix typos, give better
305
306
    Note that no users are defined by default, so add_user should
307
    be called before issuing the first request.
2420.1.11 by Vincent Ladeuil
Implement digest authentication. Test suite passes. Tested against apache-2.x.
308
    """
2420.1.9 by Vincent Ladeuil
Refactor proxy and auth test classes. Tests failing for digest auth.
309
310
    # The following attributes should be set dy daughter classes
311
    # and are used by AuthRequestHandler.
312
    auth_header_sent = None
313
    auth_header_recv = None
314
    auth_error_code = None
2420.1.11 by Vincent Ladeuil
Implement digest authentication. Test suite passes. Tested against apache-2.x.
315
    auth_realm = "Thou should not pass"
2363.4.12 by Vincent Ladeuil
Take jam's review comments into account. Fix typos, give better
316
3111.1.18 by Vincent Ladeuil
Test parametrization for protocol versions achieved. Tests are failing :)
317
    def __init__(self, request_handler, auth_scheme,
318
                 protocol_version=None):
319
        http_server.HttpServer.__init__(self, request_handler,
320
                                        protocol_version=protocol_version)
2363.4.12 by Vincent Ladeuil
Take jam's review comments into account. Fix typos, give better
321
        self.auth_scheme = auth_scheme
2363.4.8 by Vincent Ladeuil
Implement a basic auth HTTP server, rewrite tests accordingly.
322
        self.password_of = {}
2420.1.4 by Vincent Ladeuil
Add test checking the number of roundtrips due to 401 or 407 errors.
323
        self.auth_required_errors = 0
2363.4.8 by Vincent Ladeuil
Implement a basic auth HTTP server, rewrite tests accordingly.
324
325
    def add_user(self, user, password):
2363.4.12 by Vincent Ladeuil
Take jam's review comments into account. Fix typos, give better
326
        """Declare a user with an associated password.
327
328
        password can be empty, use an empty string ('') in that
329
        case, not None.
330
        """
2363.4.8 by Vincent Ladeuil
Implement a basic auth HTTP server, rewrite tests accordingly.
331
        self.password_of[user] = password
332
333
    def authorized(self, user, password):
2420.1.11 by Vincent Ladeuil
Implement digest authentication. Test suite passes. Tested against apache-2.x.
334
        """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
335
        expected_password = self.password_of.get(user, None)
336
        return expected_password is not None and password == expected_password
337
338
2420.1.19 by Vincent Ladeuil
Cosmetic changes.
339
# FIXME: There is some code duplication with
2900.2.5 by Vincent Ladeuil
ake ftp aware of authentication config.
340
# _urllib2_wrappers.py.DigestAuthHandler. If that duplication
2420.1.19 by Vincent Ladeuil
Cosmetic changes.
341
# grows, it may require a refactoring. Also, we don't implement
342
# SHA algorithm nor MD5-sess here, but that does not seem worth
343
# it.
2420.1.11 by Vincent Ladeuil
Implement digest authentication. Test suite passes. Tested against apache-2.x.
344
class DigestAuthServer(AuthServer):
345
    """A digest authentication server"""
346
2420.1.16 by Vincent Ladeuil
Handle nonce changes. Fix a nasty bug breaking the auth parameters sharing.
347
    auth_nonce = 'now!'
2420.1.11 by Vincent Ladeuil
Implement digest authentication. Test suite passes. Tested against apache-2.x.
348
3111.1.18 by Vincent Ladeuil
Test parametrization for protocol versions achieved. Tests are failing :)
349
    def __init__(self, request_handler, auth_scheme,
350
                 protocol_version=None):
351
        AuthServer.__init__(self, request_handler, auth_scheme,
352
                            protocol_version=protocol_version)
2420.1.11 by Vincent Ladeuil
Implement digest authentication. Test suite passes. Tested against apache-2.x.
353
354
    def digest_authorized(self, auth, command):
2420.1.16 by Vincent Ladeuil
Handle nonce changes. Fix a nasty bug breaking the auth parameters sharing.
355
        nonce = auth['nonce']
356
        if nonce != self.auth_nonce:
357
            return False
2420.1.11 by Vincent Ladeuil
Implement digest authentication. Test suite passes. Tested against apache-2.x.
358
        realm = auth['realm']
359
        if realm != self.auth_realm:
360
            return False
361
        user = auth['username']
362
        if not self.password_of.has_key(user):
363
            return False
364
        algorithm= auth['algorithm']
365
        if algorithm != 'MD5':
366
            return False
367
        qop = auth['qop']
368
        if qop != 'auth':
369
            return False
370
371
        password = self.password_of[user]
372
373
        # Recalculate the response_digest to compare with the one
374
        # sent by the client
375
        A1 = '%s:%s:%s' % (user, realm, password)
376
        A2 = '%s:%s' % (command, auth['uri'])
377
378
        H = lambda x: md5.new(x).hexdigest()
379
        KD = lambda secret, data: H("%s:%s" % (secret, data))
380
381
        nonce_count = int(auth['nc'], 16)
382
383
        ncvalue = '%08x' % nonce_count
384
385
        cnonce = auth['cnonce']
386
        noncebit = '%s:%s:%s:%s:%s' % (nonce, ncvalue, cnonce, qop, H(A2))
387
        response_digest = KD(H(A1), noncebit)
388
389
        return response_digest == auth['response']
390
2420.1.9 by Vincent Ladeuil
Refactor proxy and auth test classes. Tests failing for digest auth.
391
class HTTPAuthServer(AuthServer):
392
    """An HTTP server requiring authentication"""
393
2420.1.11 by Vincent Ladeuil
Implement digest authentication. Test suite passes. Tested against apache-2.x.
394
    def init_http_auth(self):
395
        self.auth_header_sent = 'WWW-Authenticate'
396
        self.auth_header_recv = 'Authorization'
397
        self.auth_error_code = 401
2420.1.9 by Vincent Ladeuil
Refactor proxy and auth test classes. Tests failing for digest auth.
398
399
400
class ProxyAuthServer(AuthServer):
401
    """A proxy server requiring authentication"""
402
2420.1.11 by Vincent Ladeuil
Implement digest authentication. Test suite passes. Tested against apache-2.x.
403
    def init_proxy_auth(self):
404
        self.proxy_requests = True
405
        self.auth_header_sent = 'Proxy-Authenticate'
406
        self.auth_header_recv = 'Proxy-Authorization'
407
        self.auth_error_code = 407
2420.1.9 by Vincent Ladeuil
Refactor proxy and auth test classes. Tests failing for digest auth.
408
409
410
class HTTPBasicAuthServer(HTTPAuthServer):
411
    """An HTTP server requiring basic authentication"""
412
3111.1.18 by Vincent Ladeuil
Test parametrization for protocol versions achieved. Tests are failing :)
413
    def __init__(self, protocol_version=None):
414
        HTTPAuthServer.__init__(self, BasicAuthRequestHandler, 'basic',
415
                                protocol_version=protocol_version)
2420.1.11 by Vincent Ladeuil
Implement digest authentication. Test suite passes. Tested against apache-2.x.
416
        self.init_http_auth()
417
418
419
class HTTPDigestAuthServer(DigestAuthServer, HTTPAuthServer):
2420.1.9 by Vincent Ladeuil
Refactor proxy and auth test classes. Tests failing for digest auth.
420
    """An HTTP server requiring digest authentication"""
421
3111.1.18 by Vincent Ladeuil
Test parametrization for protocol versions achieved. Tests are failing :)
422
    def __init__(self, protocol_version=None):
423
        DigestAuthServer.__init__(self, DigestAuthRequestHandler, 'digest',
424
                                  protocol_version=protocol_version)
2420.1.11 by Vincent Ladeuil
Implement digest authentication. Test suite passes. Tested against apache-2.x.
425
        self.init_http_auth()
2420.1.9 by Vincent Ladeuil
Refactor proxy and auth test classes. Tests failing for digest auth.
426
427
428
class ProxyBasicAuthServer(ProxyAuthServer):
2420.1.11 by Vincent Ladeuil
Implement digest authentication. Test suite passes. Tested against apache-2.x.
429
    """A proxy server requiring basic authentication"""
2420.1.9 by Vincent Ladeuil
Refactor proxy and auth test classes. Tests failing for digest auth.
430
3111.1.18 by Vincent Ladeuil
Test parametrization for protocol versions achieved. Tests are failing :)
431
    def __init__(self, protocol_version=None):
432
        ProxyAuthServer.__init__(self, BasicAuthRequestHandler, 'basic',
433
                                 protocol_version=protocol_version)
2420.1.11 by Vincent Ladeuil
Implement digest authentication. Test suite passes. Tested against apache-2.x.
434
        self.init_proxy_auth()
435
436
437
class ProxyDigestAuthServer(DigestAuthServer, ProxyAuthServer):
438
    """A proxy server requiring basic authentication"""
2420.1.9 by Vincent Ladeuil
Refactor proxy and auth test classes. Tests failing for digest auth.
439
3111.1.18 by Vincent Ladeuil
Test parametrization for protocol versions achieved. Tests are failing :)
440
    def __init__(self, protocol_version=None):
441
        ProxyAuthServer.__init__(self, DigestAuthRequestHandler, 'digest',
442
                                 protocol_version=protocol_version)
2420.1.11 by Vincent Ladeuil
Implement digest authentication. Test suite passes. Tested against apache-2.x.
443
        self.init_proxy_auth()
2420.1.9 by Vincent Ladeuil
Refactor proxy and auth test classes. Tests failing for digest auth.
444
445