Skip to content

Commit

Permalink
feat: add no cache directive to login forms (#2266)
Browse files Browse the repository at this point in the history
* feat: add no cache directive to login forms

* add test
  • Loading branch information
dpgaspar authored Aug 21, 2024
1 parent 4ddea80 commit 3030e88
Show file tree
Hide file tree
Showing 3 changed files with 31 additions and 1 deletion.
14 changes: 14 additions & 0 deletions flask_appbuilder/security/decorators.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,20 @@
P = ParamSpec("P")


def no_cache(view: Callable[..., Response]) -> Callable[..., Response]:
@functools.wraps(view)
def wrapped_view(*args, **kwargs) -> Response:
response = make_response(view(*args, **kwargs))
response.headers[
"Cache-Control"
] = "no-store, no-cache, must-revalidate, max-age=0"
response.headers["Pragma"] = "no-cache"
response.headers["Expires"] = "0"
return response

return wrapped_view


def response_unauthorized_mvc(status_code: int) -> Response:
response = make_response(
jsonify({"message": str(FLAMSG_ERR_SEC_ACCESS_DENIED), "severity": "danger"}),
Expand Down
5 changes: 4 additions & 1 deletion flask_appbuilder/security/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from flask_appbuilder.baseviews import BaseView
from flask_appbuilder.charts.views import DirectByChartView
from flask_appbuilder.fieldwidgets import BS3PasswordFieldWidget
from flask_appbuilder.security.decorators import has_access
from flask_appbuilder.security.decorators import has_access, no_cache
from flask_appbuilder.security.forms import (
DynamicForm,
LoginForm_db,
Expand Down Expand Up @@ -520,6 +520,7 @@ class AuthDBView(AuthView):
login_template = "appbuilder/general/security/login_db.html"

@expose("/login/", methods=["GET", "POST"])
@no_cache
def login(self):
if g.user is not None and g.user.is_authenticated:
return redirect(self.appbuilder.get_url_for_index)
Expand All @@ -543,6 +544,7 @@ class AuthLDAPView(AuthView):
login_template = "appbuilder/general/security/login_ldap.html"

@expose("/login/", methods=["GET", "POST"])
@no_cache
def login(self):
if g.user is not None and g.user.is_authenticated:
return redirect(self.appbuilder.get_url_for_index)
Expand All @@ -568,6 +570,7 @@ class AuthOIDView(AuthView):
oid_ask_for_optional: List[str] = []

@expose("/login/", methods=["GET", "POST"])
@no_cache
def login(self, flag=True) -> WerkzeugResponse:
@self.appbuilder.sm.oid.loginhandler
def login_handler(self):
Expand Down
13 changes: 13 additions & 0 deletions tests/security/test_mvc_security.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,19 @@ class Model1View(ModelView):

self.appbuilder.add_view(Model1View, "Model1", category="Model1")

def test_sec_login_no_cache(self):
"""
Test Security Login, no cache directives
"""
rv = self.client.get("/login/")
assert rv.status_code == 200
assert (
rv.headers.get("Cache-Control")
== "no-store, no-cache, must-revalidate, max-age=0"
)
assert rv.headers["Pragma"] == "no-cache"
assert rv.headers["Expires"] == "0"

def test_sec_login(self):
"""
Test Security Login, Logout, invalid login, invalid access
Expand Down

0 comments on commit 3030e88

Please sign in to comment.