From 1bf7a6f23b36f23511be36268cc4e1d5c0008a1b Mon Sep 17 00:00:00 2001 From: Ian Stapleton Cordasco Date: Sat, 14 Oct 2017 19:14:24 -0500 Subject: [PATCH] Add back fake cookie and make requiring it conditional Our digest auth endpoint will once again return a fake cookie but will only require it if the query-string parameter `require-cookie` is present. Further, this fixes a bug in the digest auth implementation in httpbin where we were only considering the path portions of the request-uri in the specification. RFC 7230 is very clear that the request-uri includes the query-string if it is present which means it is necessary in our digest auth handling. --- httpbin/core.py | 36 +++++++++++++++++++++++++----------- httpbin/helpers.py | 5 ++++- 2 files changed, 29 insertions(+), 12 deletions(-) diff --git a/httpbin/core.py b/httpbin/core.py index 73adcb6..6ec8990 100644 --- a/httpbin/core.py +++ b/httpbin/core.py @@ -467,44 +467,58 @@ def digest_auth_nostale(qop=None, user='user', passwd='passwd', algorithm='MD5') @app.route('/digest-auth/////') def digest_auth(qop=None, user='user', passwd='passwd', algorithm='MD5', stale_after='never'): """Prompts the user for authorization using HTTP Digest auth""" + require_cookie_handling = (request.args.get('require-cookie', '').lower() in + ('1', 't', 'true')) if algorithm not in ('MD5', 'SHA-256'): algorithm = 'MD5' if qop not in ('auth', 'auth-int'): qop = None - if 'Authorization' not in request.headers or \ - 'Cookie' not in request.headers: + authorization = request.headers.get('Authorization') + credentials = None + if authorization: + credentials = parse_authorization_header(authorization) + + if (not authorization or + not credentials or + (require_cookie_handling and 'Cookie' not in request.headers)): response = digest_challenge_response(app, qop, algorithm) response.set_cookie('stale_after', value=stale_after) + response.set_cookie('fake', value='fake_value') return response - credentails = parse_authorization_header(request.headers.get('Authorization')) - if not credentails : - response = digest_challenge_response(app, qop, algorithm) - response.set_cookie('stale_after', value=stale_after) + if (require_cookie_handling and + request.cookies.get('fake') != 'fake_value'): + response = jsonify({'errors': ['missing cookie set on challenge']}) + response.set_cookie('fake', value='fake_value') + response.status_code = 403 return response - current_nonce = credentails.get('nonce') + current_nonce = credentials.get('nonce') stale_after_value = None - if 'stale_after' in request.cookies : + if 'stale_after' in request.cookies: stale_after_value = request.cookies.get('stale_after') - if 'last_nonce' in request.cookies and current_nonce == request.cookies.get('last_nonce') or \ - stale_after_value == '0' : + if ('last_nonce' in request.cookies and + current_nonce == request.cookies.get('last_nonce') or + stale_after_value == '0'): response = digest_challenge_response(app, qop, algorithm, True) response.set_cookie('stale_after', value=stale_after) response.set_cookie('last_nonce', value=current_nonce) + response.set_cookie('fake', value='fake_value') return response - if not check_digest_auth(user, passwd) : + if not check_digest_auth(user, passwd): response = digest_challenge_response(app, qop, algorithm, False) response.set_cookie('stale_after', value=stale_after) response.set_cookie('last_nonce', value=current_nonce) + response.set_cookie('fake', value='fake_value') return response response = jsonify(authenticated=True, user=user) + response.set_cookie('fake', value='fake_value') if stale_after_value : response.set_cookie('stale_after', value=next_stale_after_value(stale_after_value)) diff --git a/httpbin/helpers.py b/httpbin/helpers.py index 6f84f50..1f50c44 100644 --- a/httpbin/helpers.py +++ b/httpbin/helpers.py @@ -358,7 +358,10 @@ def check_digest_auth(user, passwd): credentails = parse_authorization_header(request.headers.get('Authorization')) if not credentails: return - response_hash = response(credentails, passwd, dict(uri=request.script_root + request.path, + request_uri = request.script_root + request.path + if request.query_string: + request_uri += '?' + request.query_string + response_hash = response(credentails, passwd, dict(uri=request_uri, body=request.data, method=request.method)) if credentails.get('response') == response_hash: