Skip to content

Commit

Permalink
feature: Utilize want_json() for responses (#179)
Browse files Browse the repository at this point in the history
is_json() just looks at Content-Type - which in 90% of cases is fine - but in some
cases (and to be more spec-compliant) we should really be honoring the Accept header.
This adds that into all our view responses.
  • Loading branch information
jwag956 committed Sep 12, 2019
1 parent a7eac03 commit cf4402f
Show file tree
Hide file tree
Showing 4 changed files with 24 additions and 22 deletions.
2 changes: 1 addition & 1 deletion docs/customizing.rst
Original file line number Diff line number Diff line change
Expand Up @@ -293,7 +293,7 @@ tandem with Flask-Login, behaves as follows:
then if ``SECURITY_UNAUTHORIZED_VIEW`` is defined, the response will redirected.
If ``SECURITY_UNAUTHORIZED_VIEW`` is not defined, then ``abort(403)`` is called.

All this can be easily changed by defining any or all of :meth:`.Security.render_json`,
All this can be easily changed by registering any or all of :meth:`.Security.render_json`,
:meth:`.Security.unauthn_handler` and :meth:`.Security.unauthz_handler`.

The decision on whether to return JSON is based on:
Expand Down
34 changes: 17 additions & 17 deletions flask_security/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,7 @@ def login():
if not request.is_json:
return redirect(get_post_login_redirect(form.next.data))

if request.is_json:
if _security._want_json(request):
if current_user.is_authenticated:
form.user = current_user
return _base_render_json(form, include_auth_token=True)
Expand Down Expand Up @@ -267,7 +267,7 @@ def register():
# Only include auth token if in fact user is permitted to login
return _base_render_json(form, include_auth_token=did_login)

if request.is_json:
if _security._want_json(request):
return _base_render_json(form)

return _security.render_template(
Expand All @@ -293,7 +293,7 @@ def send_login():
if not request.is_json:
do_flash(*get_message("LOGIN_EMAIL_SENT", email=form.user.email))

if request.is_json:
if _security._want_json(request):
return _base_render_json(form)

return _security.render_template(
Expand Down Expand Up @@ -359,7 +359,7 @@ def send_confirmation():
if not request.is_json:
do_flash(*get_message("CONFIRMATION_REQUEST", email=form.user.email))

if request.is_json:
if _security._want_json(request):
return _base_render_json(form)

return _security.render_template(
Expand Down Expand Up @@ -456,7 +456,7 @@ def forgot_password():
if not request.is_json:
do_flash(*get_message("PASSWORD_RESET_REQUEST", email=form.user.email))

if request.is_json:
if _security._want_json(request):
return _base_render_json(form, include_user=False)

return _security.render_template(
Expand Down Expand Up @@ -562,7 +562,7 @@ def reset_password(token):
after_this_request(_commit)
update_password(user, form.password.data)
login_user(user)
if request.is_json:
if _security._want_json(request):
login_form = _security.login_form(MultiDict({"email": user.email}))
setattr(login_form, "user", user)
return _base_render_json(login_form, include_auth_token=True)
Expand All @@ -574,7 +574,7 @@ def reset_password(token):

# validation failure case - for forms - we try again including the token
# for non-forms - we just return errors and assume caller remembers token.
if request.is_json:
if _security._want_json(request):
return _base_render_json(form)
return _security.render_template(
config_value("RESET_PASSWORD_TEMPLATE"),
Expand Down Expand Up @@ -605,7 +605,7 @@ def change_password():
or get_url(_security.post_login_view)
)

if request.is_json:
if _security._want_json(request):
form.user = current_user
return _base_render_json(form, include_auth_token=True)

Expand Down Expand Up @@ -640,7 +640,7 @@ def _two_factor_login(form):
if user.tf_primary_method is None or user.tf_totp_secret is None:
session["tf_state"] = "setup_from_login"
json_response["tf_state"] = "setup_from_login"
if not request.is_json:
if not _security._want_json(request):
return redirect(url_for("two_factor_setup"))

# if user's two-factor properties are configured
Expand All @@ -653,7 +653,7 @@ def _two_factor_login(form):
user=user, method=user.tf_primary_method, totp_secret=user.tf_totp_secret
)

if not request.is_json:
if not _security._want_json(request):
return redirect(url_for("two_factor_token_validation"))

return _base_render_json(form, include_auth_token=True, additional=json_response)
Expand Down Expand Up @@ -730,7 +730,7 @@ def two_factor_setup():
tf_disable(user)
after_this_request(_commit)
do_flash(*get_message("TWO_FACTOR_DISABLED"))
if not request.is_json:
if not _security._want_json(request):
return redirect(get_url(_security.post_login_view))
else:
return _base_render_json(form)
Expand All @@ -744,7 +744,7 @@ def two_factor_setup():

send_security_token(user=user, method=pm, totp_secret=user.tf_totp_secret)
code_form = _security.two_factor_verify_code_form()
if not request.is_json:
if not _security._want_json(request):
return _security.render_template(
config_value("TWO_FACTOR_SETUP_TEMPLATE"),
two_factor_setup_form=form,
Expand All @@ -754,7 +754,7 @@ def two_factor_setup():
**_ctx("tf_setup")
)

if request.is_json:
if _security._want_json(request):
return _base_render_json(form, include_user=False)

code_form = _security.two_factor_verify_code_form()
Expand Down Expand Up @@ -841,7 +841,7 @@ def two_factor_token_validation():
return redirect(get_post_login_redirect())

# GET or not successful POST
if request.is_json:
if _security._want_json(request):
return _base_render_json(form)

# if we were trying to validate a new method
Expand Down Expand Up @@ -920,7 +920,7 @@ def two_factor_rescue():
else:
return "", 404

if request.is_json:
if _security._want_json(request):
return _base_render_json(form, include_user=False)

code_form = _security.two_factor_verify_code_form()
Expand Down Expand Up @@ -956,7 +956,7 @@ def two_factor_verify_password():
form._errors = m
return _base_render_json(form)

if request.is_json:
if _security._want_json(request):
assert form.user == current_user
# form.user = current_user
return _base_render_json(form)
Expand Down Expand Up @@ -1016,7 +1016,7 @@ def two_factor_qrcode():

def _tf_illegal_state(form, redirect_to):
m, c = get_message("TWO_FACTOR_PERMISSION_DENIED")
if not request.is_json:
if not _security._want_json(request):
do_flash(m, c)
return redirect(get_url(redirect_to))
else:
Expand Down
1 change: 0 additions & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
version = re.search(r'__version__ = "(.*?)"', f.read()).group(1)

tests_require = [
"Flask-CLI>=0.4.0",
"Flask-Mongoengine>=0.9.5",
"Flask-Peewee>=0.6.5",
"Flask-SQLAlchemy>=2.3",
Expand Down
9 changes: 6 additions & 3 deletions tests/test_common.py
Original file line number Diff line number Diff line change
Expand Up @@ -557,9 +557,12 @@ def test_login_info(client):
# Make sure we can get user info when logged in already.

json_authenticate(client)
response = client.get(
"/login", data={}, headers={"Content-Type": "application/json"}
)
response = client.get("/login", headers={"Content-Type": "application/json"})
assert response.status_code == 200
assert response.jdata["response"]["user"]["id"] == "1"
assert "last_update" in response.jdata["response"]["user"]

response = client.get("/login", headers={"Accept": "application/json"})
assert response.status_code == 200
assert response.jdata["response"]["user"]["id"] == "1"
assert "last_update" in response.jdata["response"]["user"]
Expand Down

0 comments on commit cf4402f

Please sign in to comment.