Skip to content

Commit

Permalink
feat: Require current password when change password
Browse files Browse the repository at this point in the history
  • Loading branch information
Liam committed Jan 26, 2021
1 parent d9c80f7 commit e006262
Show file tree
Hide file tree
Showing 4 changed files with 67 additions and 7 deletions.
24 changes: 24 additions & 0 deletions flask_appbuilder/security/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,30 @@ class ResetPasswordForm(DynamicForm):
)


class ResetMyPasswordForm(DynamicForm):
current_password = PasswordField(
lazy_gettext("Current Password"),
description=lazy_gettext("Your current password"),
validators=[DataRequired()],
widget=BS3PasswordFieldWidget(),
)
password = PasswordField(
lazy_gettext("Password"),
description=lazy_gettext(
"Please use a good password policy,"
" this application does not check this for you"
),
validators=[DataRequired()],
widget=BS3PasswordFieldWidget(),
)
conf_password = PasswordField(
lazy_gettext("Confirm Password"),
description=lazy_gettext("Please rewrite the password to confirm"),
validators=[EqualTo("password", message=lazy_gettext("Passwords must match"))],
widget=BS3PasswordFieldWidget(),
)


class RegisterUserDBForm(DynamicForm):
username = StringField(
lazy_gettext("User Name"),
Expand Down
21 changes: 17 additions & 4 deletions flask_appbuilder/security/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,13 @@
from wtforms.validators import EqualTo

from .decorators import has_access
from .forms import LoginForm_db, LoginForm_oid, ResetPasswordForm, UserInfoEdit
from .forms import (
LoginForm_db,
LoginForm_oid,
ResetMyPasswordForm,
ResetPasswordForm,
UserInfoEdit,
)
from .._compat import as_unicode
from ..actions import action
from ..baseviews import BaseView
Expand Down Expand Up @@ -69,12 +75,19 @@ class ResetMyPasswordView(SimpleFormView):
"""

route_base = "/resetmypassword"
form = ResetPasswordForm
route_form = f"{route_base}/form"
form = ResetMyPasswordForm
form_title = lazy_gettext("Reset Password Form")
redirect_url = "/"
message = lazy_gettext("Password Changed")
invalid_current_password_message = lazy_gettext("Invalid current password")

def form_post(self, form):
username = g.user.username
user = self.appbuilder.sm.auth_user_db(username, form.current_password.data)
if not user:
flash(as_unicode(self.invalid_current_password_message), "warning")
return redirect(self.route_form)
self.appbuilder.sm.reset_password(g.user.id, form.password.data)
flash(as_unicode(self.message), "info")

Expand Down Expand Up @@ -682,7 +695,7 @@ def oauth_authorized(self, provider):
log.debug("Authorized init")
resp = self.appbuilder.sm.oauth_remotes[provider].authorize_access_token()
if resp is None:
flash(u"You denied the request to sign in.", "warning")
flash("You denied the request to sign in.", "warning")
return redirect(self.appbuilder.get_url_for_login)
log.debug("OAUTH Authorized resp: {0}".format(resp))
# Retrieves specific user info from the provider
Expand All @@ -703,7 +716,7 @@ def oauth_authorized(self, provider):
allow = True
break
if not allow:
flash(u"You are not authorized.", "warning")
flash("You are not authorized.", "warning")
return redirect(self.appbuilder.get_url_for_login)
else:
log.debug("No whitelist for OAuth provider")
Expand Down
10 changes: 8 additions & 2 deletions flask_appbuilder/tests/test_mongoengine.py
Original file line number Diff line number Diff line change
Expand Up @@ -290,7 +290,11 @@ def test_sec_reset_password(self):
self.assertIn("Reset Password Form", data)
rv = client.post(
"/resetmypassword/form",
data=dict(password="password", conf_password="password"),
data=dict(
current_password=DEFAULT_ADMIN_PASSWORD,
password="password",
conf_password="password",
),
follow_redirects=True,
)
self.assertEqual(rv.status_code, 200)
Expand All @@ -299,7 +303,9 @@ def test_sec_reset_password(self):
rv = client.post(
"/resetmypassword/form",
data=dict(
password=DEFAULT_ADMIN_PASSWORD, conf_password=DEFAULT_ADMIN_PASSWORD
current_password="password",
password=DEFAULT_ADMIN_PASSWORD,
conf_password=DEFAULT_ADMIN_PASSWORD,
),
follow_redirects=True,
)
Expand Down
19 changes: 18 additions & 1 deletion flask_appbuilder/tests/test_mvc.py
Original file line number Diff line number Diff line change
Expand Up @@ -663,7 +663,24 @@ def test_sec_reset_password(self):
self.browser_login(client, USERNAME_ADMIN, "password")
rv = client.post(
"/resetmypassword/form",
data=dict(password=PASSWORD_ADMIN, conf_password=PASSWORD_ADMIN),
data=dict(
current_password="password",
password=PASSWORD_ADMIN,
conf_password=PASSWORD_ADMIN,
),
follow_redirects=True,
)
self.assertEqual(rv.status_code, 200)

# Reset My Password wrong current pass
self.browser_login(client, USERNAME_ADMIN, "password")
rv = client.post(
"/resetmypassword/form",
data=dict(
current_password="1",
password=PASSWORD_ADMIN,
conf_password=PASSWORD_ADMIN,
),
follow_redirects=True,
)
self.assertEqual(rv.status_code, 200)
Expand Down

0 comments on commit e006262

Please sign in to comment.