/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/transport/http/_urllib2_wrappers.py

  • Committer: Martin Pool
  • Date: 2009-03-03 03:01:49 UTC
  • mfrom: (4070 +trunk)
  • mto: This revision was merged to the branch mainline in revision 4073.
  • Revision ID: mbp@sourcefrog.net-20090303030149-8p8o8hszdtqa7w8f
merge trunk

Show diffs side-by-side

added added

removed removed

Lines of Context:
47
47
# ensure that.
48
48
 
49
49
import httplib
 
50
try:
 
51
    import kerberos
 
52
except ImportError:
 
53
    have_kerberos = False
 
54
else:
 
55
    have_kerberos = True
50
56
import socket
51
57
import urllib
52
58
import urllib2
251
257
        # Preserve our preciousss
252
258
        sock = self.sock
253
259
        self.sock = None
254
 
        # Let httplib.HTTPConnection do its housekeeping 
 
260
        # Let httplib.HTTPConnection do its housekeeping
255
261
        self.close()
256
262
        # Restore our preciousss
257
263
        self.sock = sock
365
371
 
366
372
    def __init__(self, request):
367
373
        """Constructor
368
 
        
 
374
 
369
375
        :param request: the first request sent to the proxied host, already
370
376
            processed by the opener (i.e. proxied_host is already set).
371
377
        """
692
698
                        connect.proxied_host, self.host))
693
699
            # Housekeeping
694
700
            connection.cleanup_pipe()
695
 
            # Establish the connection encryption 
 
701
            # Establish the connection encryption
696
702
            connection.connect_to_origin()
697
703
            # Propagate the connection to the original request
698
704
            request.connection = connection
943
949
    preventively set authentication headers after the first
944
950
    successful authentication.
945
951
 
946
 
    This can be used for http and proxy, as well as for basic and
 
952
    This can be used for http and proxy, as well as for basic, negotiate and
947
953
    digest authentications.
948
954
 
949
955
    This provides an unified interface for all authentication handlers
977
983
    _max_retry = 3
978
984
    """We don't want to retry authenticating endlessly"""
979
985
 
 
986
    requires_username = True
 
987
    """Whether the auth mechanism requires a username."""
 
988
 
980
989
    # The following attributes should be defined by daughter
981
990
    # classes:
982
991
    # - auth_required_header:  the header received from the server
988
997
        # in such a cycle by default.
989
998
        self._retry_count = None
990
999
 
 
1000
    def _parse_auth_header(self, server_header):
 
1001
        """Parse the authentication header.
 
1002
 
 
1003
        :param server_header: The value of the header sent by the server
 
1004
            describing the authenticaion request.
 
1005
 
 
1006
        :return: A tuple (scheme, remainder) scheme being the first word in the
 
1007
            given header (lower cased), remainder may be None.
 
1008
        """
 
1009
        try:
 
1010
            scheme, remainder = server_header.split(None, 1)
 
1011
        except ValueError:
 
1012
            scheme = server_header
 
1013
            remainder = None
 
1014
        return (scheme.lower(), remainder)
 
1015
 
991
1016
    def update_auth(self, auth, key, value):
992
1017
        """Update a value in auth marking the auth as modified if needed"""
993
1018
        old_value = auth.get(key, None)
1028
1053
                # We already tried that, give up
1029
1054
                return None
1030
1055
 
1031
 
            if auth.get('user', None) is None:
 
1056
            if self.requires_username and auth.get('user', None) is None:
1032
1057
                # Without a known user, we can't authenticate
1033
1058
                return None
1034
1059
 
1063
1088
        (digest's nonce is an example, digest's nonce_count is a
1064
1089
        *counter-example*). Such parameters must be updated by
1065
1090
        using the update_auth() method.
1066
 
        
 
1091
 
1067
1092
        :param header: The authentication header sent by the server.
1068
1093
        :param auth: The auth parameters already known. They may be
1069
1094
             updated.
1143
1168
    https_request = http_request # FIXME: Need test
1144
1169
 
1145
1170
 
 
1171
class NegotiateAuthHandler(AbstractAuthHandler):
 
1172
    """A authentication handler that handles WWW-Authenticate: Negotiate.
 
1173
 
 
1174
    At the moment this handler supports just Kerberos. In the future,
 
1175
    NTLM support may also be added.
 
1176
    """
 
1177
 
 
1178
    handler_order = 480
 
1179
 
 
1180
    requires_username = False
 
1181
 
 
1182
    def auth_match(self, header, auth):
 
1183
        scheme, raw_auth = self._parse_auth_header(header)
 
1184
        if scheme != 'negotiate':
 
1185
            return False
 
1186
        self.update_auth(auth, 'scheme', scheme)
 
1187
        resp = self._auth_match_kerberos(auth)
 
1188
        if resp is None:
 
1189
            return False
 
1190
        # Optionally should try to authenticate using NTLM here
 
1191
        self.update_auth(auth, 'negotiate_response', resp)
 
1192
        return True
 
1193
 
 
1194
    def _auth_match_kerberos(self, auth):
 
1195
        """Try to create a GSSAPI response for authenticating against a host."""
 
1196
        if not have_kerberos:
 
1197
            return None
 
1198
        ret, vc = kerberos.authGSSClientInit("HTTP@%(host)s" % auth)
 
1199
        if ret < 1:
 
1200
            trace.warning('Unable to create GSSAPI context for %s: %d',
 
1201
                auth['host'], ret)
 
1202
            return None
 
1203
        ret = kerberos.authGSSClientStep(vc, "")
 
1204
        if ret < 0:
 
1205
            trace.mutter('authGSSClientStep failed: %d', ret)
 
1206
            return None
 
1207
        return kerberos.authGSSClientResponse(vc)
 
1208
 
 
1209
    def build_auth_header(self, auth, request):
 
1210
        return "Negotiate %s" % auth['negotiate_response']
 
1211
 
 
1212
    def auth_params_reusable(self, auth):
 
1213
        # If the auth scheme is known, it means a previous
 
1214
        # authentication was successful, all information is
 
1215
        # available, no further checks are needed.
 
1216
        return (auth.get('scheme', None) == 'negotiate' and
 
1217
                auth.get('negotiate_response', None) is not None)
 
1218
 
 
1219
 
1146
1220
class BasicAuthHandler(AbstractAuthHandler):
1147
1221
    """A custom basic authentication handler."""
1148
1222
 
1156
1230
        return auth_header
1157
1231
 
1158
1232
    def auth_match(self, header, auth):
1159
 
        scheme, raw_auth = header.split(None, 1)
1160
 
        scheme = scheme.lower()
 
1233
        scheme, raw_auth = self._parse_auth_header(header)
1161
1234
        if scheme != 'basic':
1162
1235
            return False
1163
1236
 
1204
1277
class DigestAuthHandler(AbstractAuthHandler):
1205
1278
    """A custom digest authentication handler."""
1206
1279
 
1207
 
    # Before basic as digest is a bit more secure
 
1280
    # Before basic as digest is a bit more secure and should be preferred
1208
1281
    handler_order = 490
1209
1282
 
1210
1283
    def auth_params_reusable(self, auth):
1214
1287
        return auth.get('scheme', None) == 'digest'
1215
1288
 
1216
1289
    def auth_match(self, header, auth):
1217
 
        scheme, raw_auth = header.split(None, 1)
1218
 
        scheme = scheme.lower()
 
1290
        scheme, raw_auth = self._parse_auth_header(header)
1219
1291
        if scheme != 'digest':
1220
1292
            return False
1221
1293
 
1368
1440
    """Custom proxy basic authentication handler"""
1369
1441
 
1370
1442
 
 
1443
class HTTPNegotiateAuthHandler(NegotiateAuthHandler, HTTPAuthHandler):
 
1444
    """Custom http negotiate authentication handler"""
 
1445
 
 
1446
 
 
1447
class ProxyNegotiateAuthHandler(NegotiateAuthHandler, ProxyAuthHandler):
 
1448
    """Custom proxy negotiate authentication handler"""
 
1449
 
 
1450
 
1371
1451
class HTTPErrorProcessor(urllib2.HTTPErrorProcessor):
1372
1452
    """Process HTTP error responses.
1373
1453
 
1432
1512
            ProxyHandler(),
1433
1513
            HTTPBasicAuthHandler(),
1434
1514
            HTTPDigestAuthHandler(),
 
1515
            HTTPNegotiateAuthHandler(),
1435
1516
            ProxyBasicAuthHandler(),
1436
1517
            ProxyDigestAuthHandler(),
 
1518
            ProxyNegotiateAuthHandler(),
1437
1519
            HTTPHandler,
1438
1520
            HTTPSHandler,
1439
1521
            HTTPDefaultErrorHandler,