Fix HTTP Basic Auth popups caused by auth failures.

If a user's session cookie expired, the next REST API request their
browser did would go into the json_unauthorized code path.  This
returned a response with a WWW-Authenticate tag for HTTP Basic Auth
(since that's what the REST API uses), even for /json requests which
should only be authenticated using session auth.

We fix this by explicitly passing the desired WWW-Authenticate state.

Fixes: #800.
This commit is contained in:
Tim Abbott 2016-05-17 18:42:07 -07:00
parent 45beac7d6c
commit 250781e843
2 changed files with 15 additions and 7 deletions

View File

@ -10,14 +10,19 @@ from six import text_type
class HttpResponseUnauthorized(HttpResponse):
status_code = 401
def __init__(self, realm):
# type (text_type) -> None
def __init__(self, realm, www_authenticate=None):
# type (text_type, Optional[text_type]) -> None
HttpResponse.__init__(self)
if www_authenticate is None:
self["WWW-Authenticate"] = 'Basic realm="%s"' % (realm,)
elif www_authenticate == "session":
self["WWW-Authenticate"] = 'Session realm="%s"' % (realm,)
else:
raise Exception("Invalid www_authenticate value!")
def json_unauthorized(message):
# type: (text_type) -> text_type
resp = HttpResponseUnauthorized("zulip")
def json_unauthorized(message, www_authenticate=None):
# type: (text_type, Optional[text_type]) -> HttpResponse
resp = HttpResponseUnauthorized("zulip", www_authenticate=www_authenticate)
resp.content = ujson.dumps({"result": "error",
"msg": message}) + "\n"
return resp

View File

@ -83,8 +83,11 @@ def rest_dispatch(request, globals_list, **kwargs):
# If this looks like a request from a top-level page in a
# browser, send the user to the login page
return HttpResponseRedirect('%s/?next=%s' % (settings.HOME_NOT_LOGGED_IN, request.path))
else:
elif request.path.startswith("/api"):
return json_unauthorized(_("Not logged in: API authentication or user session required"))
else:
return json_unauthorized(_("Not logged in: API authentication or user session required"),
www_authenticate='session')
if request.method not in ["GET", "POST"]:
# process_as_post needs to be the outer decorator, because