692
698
connect.proxied_host, self.host))
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.
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.
949
955
This provides an unified interface for all authentication handlers
988
997
# in such a cycle by default.
989
998
self._retry_count = None
1000
def _parse_auth_header(self, server_header):
1001
"""Parse the authentication header.
1003
:param server_header: The value of the header sent by the server
1004
describing the authenticaion request.
1006
:return: A tuple (scheme, remainder) scheme being the first word in the
1007
given header (lower cased), remainder may be None.
1010
scheme, remainder = server_header.split(None, 1)
1012
scheme = server_header
1014
return (scheme.lower(), remainder)
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
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
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.
1067
1092
:param header: The authentication header sent by the server.
1068
1093
:param auth: The auth parameters already known. They may be
1143
1168
https_request = http_request # FIXME: Need test
1171
class NegotiateAuthHandler(AbstractAuthHandler):
1172
"""A authentication handler that handles WWW-Authenticate: Negotiate.
1174
At the moment this handler supports just Kerberos. In the future,
1175
NTLM support may also be added.
1180
requires_username = False
1182
def auth_match(self, header, auth):
1183
scheme, raw_auth = self._parse_auth_header(header)
1184
if scheme != 'negotiate':
1186
self.update_auth(auth, 'scheme', scheme)
1187
resp = self._auth_match_kerberos(auth)
1190
# Optionally should try to authenticate using NTLM here
1191
self.update_auth(auth, 'negotiate_response', resp)
1194
def _auth_match_kerberos(self, auth):
1195
"""Try to create a GSSAPI response for authenticating against a host."""
1196
if not have_kerberos:
1198
ret, vc = kerberos.authGSSClientInit("HTTP@%(host)s" % auth)
1200
trace.warning('Unable to create GSSAPI context for %s: %d',
1203
ret = kerberos.authGSSClientStep(vc, "")
1205
trace.mutter('authGSSClientStep failed: %d', ret)
1207
return kerberos.authGSSClientResponse(vc)
1209
def build_auth_header(self, auth, request):
1210
return "Negotiate %s" % auth['negotiate_response']
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)
1146
1220
class BasicAuthHandler(AbstractAuthHandler):
1147
1221
"""A custom basic authentication handler."""
1156
1230
return auth_header
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':
1204
1277
class DigestAuthHandler(AbstractAuthHandler):
1205
1278
"""A custom digest authentication handler."""
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
1210
1283
def auth_params_reusable(self, auth):
1214
1287
return auth.get('scheme', None) == 'digest'
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':
1368
1440
"""Custom proxy basic authentication handler"""
1443
class HTTPNegotiateAuthHandler(NegotiateAuthHandler, HTTPAuthHandler):
1444
"""Custom http negotiate authentication handler"""
1447
class ProxyNegotiateAuthHandler(NegotiateAuthHandler, ProxyAuthHandler):
1448
"""Custom proxy negotiate authentication handler"""
1371
1451
class HTTPErrorProcessor(urllib2.HTTPErrorProcessor):
1372
1452
"""Process HTTP error responses.