Skip to content

Commit ba3154c

Browse files
committed
Warn rather than raise on opportunistic auth failure.
When opportunistic_auth is enabled but an Authorization header could not be generated opportunistically, log a warning rather than raising an exception. (If the request results in a 401 and we fail to generate an Authorization header in that (no- longer-opportunistic) case, an exception is still raised.) Also, never log Authorization header values to prevent unintentional leaking of credentials.
1 parent 492a4ab commit ba3154c

File tree

2 files changed

+38
-23
lines changed

2 files changed

+38
-23
lines changed

HISTORY.rst

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,18 @@
11
History
22
=======
33

4+
Unreleased
5+
----------
6+
7+
- When opportunistic_auth is enabled but an Authorization header
8+
could not be generated opportunistically, log a warning rather
9+
than raising an exception. (If the request results in a 401
10+
and we fail to generate an Authorization header in that (no-
11+
longer-opportunistic) case, an exception is still raised.)
12+
13+
- Never log Authorization header values to prevent unintentional
14+
leaking of credentials.
15+
416
1.2.3: 2021-02-08
517
-----------------
618

requests_gssapi/gssapi_.py

Lines changed: 26 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -159,8 +159,8 @@ def generate_request_header(self, response, host, is_preemptive=False):
159159
except gssapi.exceptions.GSSError as error:
160160
msg = error.gen_message()
161161
log.exception(
162-
"generate_request_header(): {0} failed:".format(gss_stage))
163-
log.exception(msg)
162+
"generate_request_header(): %s failed: %s", gss_stage, msg
163+
)
164164
raise SPNEGOExchangeError("%s failed: %s" % (gss_stage, msg))
165165

166166
def authenticate_user(self, response, **kwargs):
@@ -174,8 +174,7 @@ def authenticate_user(self, response, **kwargs):
174174
# GSS Failure, return existing response
175175
return response
176176

177-
log.debug("authenticate_user(): Authorization header: {0}".format(
178-
auth_header))
177+
log.debug("authenticate_user(): adding Authorization header")
179178
response.request.headers['Authorization'] = auth_header
180179

181180
# Consume the content so we can reuse the connection for the next
@@ -186,7 +185,7 @@ def authenticate_user(self, response, **kwargs):
186185
_r = response.connection.send(response.request, **kwargs)
187186
_r.history.append(response)
188187

189-
log.debug("authenticate_user(): returning {0}".format(_r))
188+
log.debug("authenticate_user(): returning %s", _r)
190189
return _r
191190

192191
def handle_401(self, response, **kwargs):
@@ -195,11 +194,13 @@ def handle_401(self, response, **kwargs):
195194
log.debug("handle_401(): Handling: 401")
196195
if _negotiate_value(response) is not None:
197196
_r = self.authenticate_user(response, **kwargs)
198-
log.debug("handle_401(): returning {0}".format(_r))
197+
log.debug("handle_401(): returning %s", _r)
199198
return _r
200199
else:
201-
log.debug("handle_401(): GSSAPI is not supported")
202-
log.debug("handle_401(): returning {0}".format(response))
200+
log.debug(
201+
"handle_401(): GSSAPI is not supported -> returning %s",
202+
response,
203+
)
203204
return response
204205

205206
def handle_other(self, response):
@@ -210,7 +211,7 @@ def handle_other(self, response):
210211
log.debug("handle_other(): Handling: %d" % response.status_code)
211212

212213
if self.mutual_authentication not in (REQUIRED, OPTIONAL):
213-
log.debug("handle_other(): returning {0}".format(response))
214+
log.debug("handle_other(): returning %s", response)
214215
return response
215216

216217
is_http_error = response.status_code >= 400
@@ -226,13 +227,15 @@ def handle_other(self, response):
226227
"Unable to authenticate {0}".format(response))
227228

228229
# Authentication successful
229-
log.debug("handle_other(): returning {0}".format(response))
230+
log.debug("handle_other(): returning %s", response)
230231
return response
231232
elif is_http_error or self.mutual_authentication == OPTIONAL:
232233
if not response.ok:
233234
log.error(
234235
"handle_other(): Mutual authentication unavailable on"
235-
" {0} response".format(response.status_code))
236+
" %s response",
237+
response.status_code,
238+
)
236239

237240
if self.mutual_authentication == REQUIRED and \
238241
self.sanitize_mutual_error_response:
@@ -252,10 +255,6 @@ def authenticate_server(self, response):
252255
253256
Returns True on success, False on failure.
254257
"""
255-
256-
log.debug("authenticate_server(): Authenticate header: {0}".format(
257-
_negotiate_value(response)))
258-
259258
host = urlparse(response.url).hostname
260259

261260
try:
@@ -306,14 +305,18 @@ def __call__(self, request):
306305
# by the 401 handler
307306
host = urlparse(request.url).hostname
308307

309-
auth_header = self.generate_request_header(None, host,
310-
is_preemptive=True)
311-
312-
log.debug(
313-
"HTTPSPNEGOAuth: Preemptive Authorization header: {0}"
314-
.format(auth_header))
315-
316-
request.headers['Authorization'] = auth_header
308+
try:
309+
auth_header = self.generate_request_header(None, host,
310+
is_preemptive=True)
311+
except SPNEGOExchangeError as exc:
312+
log.warning(
313+
"HTTPSPNEGOAuth: Opportunistic auth failed with %s ->"
314+
" sending request without adding Authorization header",
315+
exc,
316+
)
317+
else:
318+
log.debug("HTTPSPNEGOAuth: Adding opportunistic auth header")
319+
request.headers['Authorization'] = auth_header
317320

318321
request.register_hook('response', self.handle_response)
319322
try:

0 commit comments

Comments
 (0)