1035
1038
# Let's be ready for next round
1036
1039
self._retry_count = None
1038
server_header = headers.get(self.auth_required_header, None)
1039
if server_header is None:
1041
server_headers = headers.getheaders(self.auth_required_header)
1042
if not server_headers:
1040
1043
# The http error MUST have the associated
1041
1044
# header. This must never happen in production code.
1042
1045
raise KeyError('%s not found' % self.auth_required_header)
1044
1047
auth = self.get_auth(request)
1045
1048
auth['modified'] = False
1046
if self.auth_match(server_header, auth):
1047
# auth_match may have modified auth (by adding the
1048
# password or changing the realm, for example)
1049
if (request.get_header(self.auth_header, None) is not None
1050
and not auth['modified']):
1051
# We already tried that, give up
1054
if self.requires_username and auth.get('user', None) is None:
1055
# Without a known user, we can't authenticate
1059
request.connection.cleanup_pipe()
1060
response = self.parent.open(request)
1062
self.auth_successful(request, response)
1049
# FIXME: the auth handler should be selected at a single place instead
1050
# of letting all handlers try to match all headers, but the current
1051
# design doesn't allow a simple implementation.
1052
for server_header in server_headers:
1053
# Several schemes can be proposed by the server, try to match each
1055
matching_handler = self.auth_match(server_header, auth)
1056
if matching_handler:
1057
# auth_match may have modified auth (by adding the
1058
# password or changing the realm, for example)
1059
if (request.get_header(self.auth_header, None) is not None
1060
and not auth['modified']):
1061
# We already tried that, give up
1064
# Only the most secure scheme proposed by the server should be
1065
# used, since the handlers use 'handler_order' to describe that
1066
# property, the first handler tried takes precedence, the
1067
# others should not attempt to authenticate if the best one
1069
best_scheme = auth.get('best_scheme', None)
1070
if best_scheme is None:
1071
# At that point, if current handler should doesn't succeed
1072
# the credentials are wrong (or incomplete), but we know
1073
# that the associated scheme should be used.
1074
best_scheme = auth['best_scheme'] = self.scheme
1075
if best_scheme != self.scheme:
1078
if self.requires_username and auth.get('user', None) is None:
1079
# Without a known user, we can't authenticate
1083
request.connection.cleanup_pipe()
1084
# Retry the request with an authentication header added
1085
response = self.parent.open(request)
1087
self.auth_successful(request, response)
1064
1089
# We are not qualified to handle the authentication.
1065
1090
# Note: the authentication error handling will try all
1066
1091
# available handlers. If one of them authenticates
1192
1217
NTLM support may also be added.
1220
scheme = 'negotiate'
1195
1221
handler_order = 480
1197
1222
requires_username = False
1199
1224
def auth_match(self, header, auth):
1200
1225
scheme, raw_auth = self._parse_auth_header(header)
1201
if scheme != 'negotiate':
1226
if scheme != self.scheme:
1203
1228
self.update_auth(auth, 'scheme', scheme)
1204
1229
resp = self._auth_match_kerberos(auth)
1256
1281
def auth_match(self, header, auth):
1257
1282
scheme, raw_auth = self._parse_auth_header(header)
1258
if scheme != 'basic':
1283
if scheme != self.scheme:
1261
1286
match, realm = self.extract_realm(raw_auth)
1263
if scheme != 'basic':
1266
1288
# Put useful info into auth
1267
1289
self.update_auth(auth, 'scheme', scheme)
1268
1290
self.update_auth(auth, 'realm', realm)